/*
	lime_crypto-tester.cpp
	@author Johan Pascal
	@copyright 	Copyright (C) 2018  Belledonne Communications SARL

	This program is free software: you can redistribute it and/or modify
	it under the terms of the GNU General Public License as published by
	the Free Software Foundation, either version 3 of the License, or
	(at your option) any later version.

	This program is distributed in the hope that it will be useful,
	but WITHOUT ANY WARRANTY; without even the implied warranty of
	MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
	GNU General Public License for more details.

	You should have received a copy of the GNU General Public License
	along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

#include "lime_log.hpp"
#include "lime-tester.hpp"
#include "lime-tester-utils.hpp"
#include "lime_keys.hpp"
#include "lime_crypto_primitives.hpp"

#include <bctoolbox/tester.h>
#include <bctoolbox/port.h>
#include <bctoolbox/exception.hh>
#include <iostream>
#include <fstream>
#include <sstream>
#include <string>
#include <stdio.h>
#include <string.h>

using namespace::std;
using namespace::lime;

constexpr uint64_t BENCH_TIMING_MS=200;

/* Function */
static void snprintSI(std::string &output, double x, const char *unit, const char *spacer = " ") {
	const char *_small[] = {" ","m","µ","n","p"};
	const char *_big[] = {" ","k","M","G","T"};

	constexpr size_t tempBufferSize = 100;
	char tempBuffer[tempBufferSize]; // hoping no one will use this function to print more than 100 chars...

	if (12+strlen(spacer)+strlen(unit)>sizeof(tempBuffer)) {// 6 digit, 1 point, 2 digits + unit + 1 prefix + spacer + NULL term
	throw BCTBX_EXCEPTION << "snprintSI tmpBuffer is too small to hold your data";
	}

	if (x < 1) {
		unsigned di=0;
		for (di=0; di<sizeof(_small)/sizeof(*_small)-1 && x && x < 1; di++) {
			x *= 1000.0;
		}
		snprintf(tempBuffer, sizeof(tempBuffer), "%6.2f%s%s%s", x, spacer, _small[di], unit);
	} else {
		unsigned di=0;
		for (di=0; di<sizeof(_big)/sizeof(*_big)-1 && x && x >= 1000; di++) {
			x /= 1000.0;
		}
		snprintf(tempBuffer, sizeof(tempBuffer), "%6.2f%s%s%s", x, spacer, _big[di], unit);
	}

	output = tempBuffer;
}

template <typename Curve>
void keyExchange_test(void) {
	/* We need a RNG */
	std::shared_ptr<RNG> rng = make_RNG();
	/* Create Alice and Bob ECDH context */
	std::shared_ptr<keyExchange<Curve>> Alice = make_keyExchange<Curve>();
	std::shared_ptr<keyExchange<Curve>> Bob = make_keyExchange<Curve>();

	/* Generate key pairs */
	Alice->createKeyPair(rng);
	Bob->createKeyPair(rng);

	/* Exchange keys */
	Alice->set_peerPublic(Bob->get_selfPublic());
	Bob->set_peerPublic(Alice->get_selfPublic());

	/* Compute shared secret */
	Alice->computeSharedSecret();
	Bob->computeSharedSecret();

	/* Compare them */
	BC_ASSERT_TRUE(Alice->get_sharedSecret()==Bob->get_sharedSecret());
}

template <typename Curve>
void keyExchange_bench(uint64_t runTime_ms) {
	constexpr size_t batch_size = 100;

	/* We need a RNG */
	std::shared_ptr<RNG> rng = make_RNG();

	/* Create Alice and Bob ECDH context */
	std::shared_ptr<keyExchange<Curve>> Alice = make_keyExchange<Curve>();
	std::shared_ptr<keyExchange<Curve>> Bob = make_keyExchange<Curve>();

	auto start = bctbx_get_cur_time_ms();
	uint64_t span=0;
	size_t runCount = 0;

	while (span<runTime_ms) {
		for (size_t i=0; i<batch_size; i++) {
			/* Generate key pairs */
			Alice->createKeyPair(rng);
			Bob->createKeyPair(rng);
		}
		span = bctbx_get_cur_time_ms() - start;
		runCount += batch_size;
	}

	auto freq = 2000*runCount/static_cast<double>(span);
	std::string freq_unit, period_unit;
	snprintSI(freq_unit, freq, "keys/s");
	snprintSI(period_unit, 1/freq, "s/keys");
	LIME_LOGI<<"Key generation "<<int(2*runCount)<<" ECDH keys in "<<int(span)<<" ms : "<<period_unit<<" "<<freq_unit<<endl;

	/* Exchange keys */
	Alice->set_peerPublic(Bob->get_selfPublic());
	Bob->set_peerPublic(Alice->get_selfPublic());

	start = bctbx_get_cur_time_ms();
	span=0;
	runCount = 0;

	while (span<runTime_ms) {
		for (size_t i=0; i<batch_size; i++) {
			/* Compute shared secret */
			Alice->computeSharedSecret();
		}
		span = bctbx_get_cur_time_ms() - start;
		runCount += batch_size;
	}
	freq = 1000*runCount/static_cast<double>(span);
	snprintSI(freq_unit, freq, "computations/s");
	snprintSI(period_unit, 1/freq, "s/computation");
	LIME_LOGI<<"Shared Secret "<<int(runCount)<<" computations in "<<int(span)<<" ms : "<<period_unit<<" "<<freq_unit<<endl<<endl;
}

static void exchange(void) {
#ifdef EC25519_ENABLED
	keyExchange_test<C255>();
	if (bench) {
		LIME_LOGI<<"Bench for Curve 25519:"<<endl;
		keyExchange_bench<C255>(BENCH_TIMING_MS);
	}
#endif
#ifdef EC448_ENABLED
	keyExchange_test<C448>();
	if (bench) {
		LIME_LOGI<<"Bench for Curve 448:"<<endl;
		keyExchange_bench<C448>(BENCH_TIMING_MS);
	}
#endif
}

/**
 * Testing sign, verify and DSA to keyEchange key conversion
 * Scenario:
 * - Alice and Bob generate a Signature key pair
 * - They both sign a message, exchange it and verify it
 * - each of them convert their private Signature key into a private keyExchange one and derive the matching public key
 * - each of them convert the peer Signature public key into a keyExchange public key
 * - both compute the shared secret and compare
 */
template <typename Curve>
void signAndVerify_test(void) {
	/* We need a RNG */
	auto rng = make_RNG();
	/* Create Alice, Bob, Vera Signature context */
	auto AliceDSA = make_Signature<Curve>();
	auto BobDSA = make_Signature<Curve>();
	auto Vera = make_Signature<Curve>();

	std::string aliceMessageString{"Lluchiwn ein gwydrau achos Ni yw y byd Ni yw y byd, Ni yw y byd, Carwn ein gelynion achos Ni yw y byd. Ni yw y byd, dewch bawb ynghyd, Tynnwn ein dillad achos Ni yw y byd. Ni yw y byd, Ni yw y byd, Dryswn ein cyfoedion achos Ni yw y byd. Ni yw y byd, dewch bawb ynghyd, Gwaeddwn yn llawen achos Ni yw y byd."};
	std::string bobMessageString{"Neidiwn i'r awyr achos ni yw y byd Ni yw y byd, dewch bawb ynghyd, Chwalwn ddisgyrchiant achos Ni yw y byd, Rowliwn yn y rhedyn achos Ni yw y byd. Rhyddhawn ein penblethau! Ni yw y byd, dewch bawb ynghyd, Paratown am chwyldro achos Ni yw y byd"};
	std::vector<uint8_t> aliceMessage{aliceMessageString.cbegin(), aliceMessageString.cend()};
	std::vector<uint8_t> bobMessage{bobMessageString.cbegin(), bobMessageString.cend()};

	/* Generate Signature key pairs */
	AliceDSA->createKeyPair(rng);
	BobDSA->createKeyPair(rng);

	/* Sign messages*/
	DSA<Curve, lime::DSAtype::signature> aliceSignature;
	DSA<Curve, lime::DSAtype::signature> bobSignature;
	AliceDSA->sign(aliceMessage, aliceSignature);
	BobDSA->sign(bobMessage, bobSignature);

	/* Vera check messages authenticity */
	Vera->set_public(AliceDSA->get_public());
	BC_ASSERT_TRUE(Vera->verify(aliceMessage, aliceSignature));
	BC_ASSERT_FALSE(Vera->verify(bobMessage, aliceSignature));
	Vera->set_public(BobDSA->get_public());
	BC_ASSERT_FALSE(Vera->verify(aliceMessage, bobSignature));
	BC_ASSERT_TRUE(Vera->verify(bobMessage, bobSignature));

	/* Bob and Alice create keyExchange context */
	auto AliceKeyExchange = make_keyExchange<Curve>();
	auto BobKeyExchange = make_keyExchange<Curve>();

	/* Convert keys */
	AliceKeyExchange->set_secret(AliceDSA->get_secret()); // auto convert from DSA to X format
	AliceKeyExchange->deriveSelfPublic(); // derive public from private
	AliceKeyExchange->set_peerPublic(BobDSA->get_public()); // import Bob DSA public key

	BobKeyExchange->set_secret(BobDSA->get_secret()); // convert from DSA to X format
	BobKeyExchange->set_selfPublic(BobDSA->get_public()); // convert from DSA to X format
	BobKeyExchange->set_peerPublic(AliceDSA->get_public()); // import Alice DSA public key

	/* Compute shared secret */
	AliceKeyExchange->computeSharedSecret();
	BobKeyExchange->computeSharedSecret();

	/* Compare them */
	BC_ASSERT_TRUE(AliceKeyExchange->get_sharedSecret()==BobKeyExchange->get_sharedSecret());
}

template <typename Curve>
void signAndVerify_bench(uint64_t runTime_ms ) {
	constexpr size_t batch_size = 100;

	/* We need a RNG */
	auto rng = make_RNG();
	/* Create Alice, Vera Signature context */
	auto Alice = make_Signature<Curve>();
	auto Vera = make_Signature<Curve>();

	// the message to sign is a public Key for keyExchange algo
	auto keyExchangeContext = make_keyExchange<Curve>();
	keyExchangeContext->createKeyPair(rng);
	auto XpublicKey = keyExchangeContext->get_selfPublic();

	auto start = bctbx_get_cur_time_ms();
	uint64_t span=0;
	size_t runCount = 0;

	while (span<runTime_ms) {
		for (size_t i=0; i<batch_size; i++) {
			/* Generate Signature key pairs */
			Alice->createKeyPair(rng);
		}
		span = bctbx_get_cur_time_ms() - start;
		runCount += batch_size;
	}

	auto freq = 1000*runCount/static_cast<double>(span);
	std::string freq_unit, period_unit;
	snprintSI(freq_unit, freq, "generations/s");
	snprintSI(period_unit, 1/freq, "s/generation");
	LIME_LOGI<<"Generate "<<int(runCount)<<" Signature key pairs in "<<int(span)<<" ms : "<<period_unit<<" "<<freq_unit<<endl;

	start = bctbx_get_cur_time_ms();
	span=0;
	runCount = 0;

	/* Sign messages*/
	DSA<Curve, lime::DSAtype::signature> aliceSignature;

	while (span<runTime_ms) {
		for (size_t i=0; i<batch_size; i++) {
			Alice->sign(XpublicKey, aliceSignature);
		}
		span = bctbx_get_cur_time_ms() - start;
		runCount += batch_size;
	}

	freq = 1000*runCount/static_cast<double>(span);
	snprintSI(freq_unit, freq, "signatures/s");
	snprintSI(period_unit, 1/freq, "s/signature");
	LIME_LOGI<<"Sign "<<int(runCount)<<" messages "<<int(span)<<" ms : "<<period_unit<<" "<<freq_unit<<endl;

	start = bctbx_get_cur_time_ms();
	span=0;
	runCount = 0;
	/* Vera check messages authenticity */
	Vera->set_public(Alice->get_public());
	while (span<runTime_ms) {
		for (size_t i=0; i<batch_size; i++) {
			Vera->verify(XpublicKey, aliceSignature);
		}
		span = bctbx_get_cur_time_ms() - start;
		runCount += batch_size;
	}

	freq = 1000*runCount/static_cast<double>(span);
	snprintSI(freq_unit, freq, "verifies/s");
	snprintSI(period_unit, 1/freq, "s/verify");
	LIME_LOGI<<"Verify "<<int(runCount)<<" messages "<<int(span)<<" ms : "<<period_unit<<" "<<freq_unit<<endl<<endl;

	BC_ASSERT_TRUE(Vera->verify(XpublicKey, aliceSignature));
}

static void signAndVerify(void) {
#ifdef EC25519_ENABLED
	signAndVerify_test<C255>();
	if (bench) {
		LIME_LOGI<<"Bench for Curve 25519:"<<endl;
		signAndVerify_bench<C255>(BENCH_TIMING_MS);
	}

	/* pattern self generated as we use a eddsa25519ctx with a zero sized context which is not a common setting */
	constexpr size_t c255_patternsSize = 8;
	std::array<std::vector<uint8_t>, c255_patternsSize> c255_secret_keys = {{
		std::vector<uint8_t>{0xd2, 0x1a, 0x80, 0x79, 0x77, 0x5d, 0x9b, 0xfd, 0x99, 0xd8, 0x66, 0xcd, 0x16, 0xa7, 0x59, 0xcc, 0xfe, 0xf5, 0xdb, 0xab, 0x49, 0xc6, 0xf3, 0x0f, 0x09, 0x24, 0xc8, 0x56, 0x95, 0xac, 0x02, 0x97},
		std::vector<uint8_t>{0x42, 0xf8, 0x2c, 0x1a, 0xff, 0x50, 0x39, 0x8b, 0x07, 0x3d, 0x1e, 0x68, 0x2e, 0xf5, 0x9d, 0xda, 0x77, 0x9b, 0x54, 0xea, 0x99, 0xd6, 0x58, 0xf5, 0xd3, 0xeb, 0x88, 0xbb, 0x79, 0xfc, 0x3f, 0x28},
		std::vector<uint8_t>{0x23, 0x74, 0xff, 0xdc, 0xd7, 0x11, 0x73, 0xd8, 0x50, 0xbf, 0x81, 0xdc, 0xce, 0x9f, 0x73, 0x94, 0x08, 0x8f, 0xba, 0xe3, 0xbd, 0x61, 0x9a, 0xb4, 0x77, 0x50, 0xce, 0xd0, 0xc3, 0x53, 0x79, 0x3d},
		std::vector<uint8_t>{0x3c, 0xee, 0xdb, 0x12, 0x17, 0x32, 0xaf, 0xfb, 0xec, 0xb5, 0xf5, 0xca, 0x50, 0xcd, 0x37, 0x22, 0x46, 0xc4, 0xd7, 0x81, 0xcf, 0xed, 0x07, 0x26, 0x14, 0x58, 0x25, 0xe6, 0xea, 0x6e, 0x91, 0xd2},
		std::vector<uint8_t>{0x24, 0x0b, 0xb2, 0x13, 0x55, 0x81, 0x3e, 0x9a, 0x62, 0xc6, 0x3c, 0xac, 0x6d, 0x39, 0xd6, 0xff, 0xc0, 0x76, 0xc2, 0x4e, 0x30, 0x3d, 0xd9, 0x86, 0x92, 0x00, 0xd5, 0x75, 0x90, 0x34, 0xf7, 0xdf},
		std::vector<uint8_t>{0xe8, 0xe9, 0x9a, 0x85, 0x8a, 0xc1, 0x91, 0x14, 0xb9, 0x9c, 0x47, 0x53, 0xa4, 0x9c, 0xd1, 0x4e, 0x15, 0x49, 0x4c, 0xd2, 0x58, 0x23, 0x76, 0xe6, 0x83, 0x40, 0x11, 0x37, 0x08, 0x2e, 0x5e, 0x9e},
		std::vector<uint8_t>{0x6f, 0x85, 0xbc, 0xaa, 0x4d, 0xa8, 0x2d, 0xaf, 0x30, 0xe9, 0x5e, 0x41, 0x02, 0x30, 0x4e, 0xa9, 0x80, 0x05, 0xb2, 0x6e, 0xc4, 0xfe, 0xbf, 0x6b, 0x08, 0xd3, 0xe7, 0xe7, 0x1c, 0x3c, 0x9e, 0xc0},
		std::vector<uint8_t>{0xc0, 0x2a, 0x76, 0x4c, 0xc1, 0xe9, 0x72, 0x44, 0xf5, 0x65, 0x35, 0x84, 0xf0, 0x24, 0xc6, 0x7d, 0x4a, 0x4f, 0x05, 0x38, 0x2b, 0xbf, 0x0e, 0xa4, 0x3b, 0x24, 0x83, 0xa7, 0xd2, 0x2d, 0xdf, 0xb7}
	}};

	std::array<std::vector<uint8_t>, c255_patternsSize> c255_public_keys = {{
		std::vector<uint8_t>{0x34, 0xe5, 0x65, 0x6c, 0x75, 0x48, 0x98, 0x1d, 0x15, 0x52, 0x70, 0x3e, 0x10, 0x53, 0x28, 0xca, 0xde, 0xe4, 0xe6, 0x0c, 0x7f, 0xc2, 0x8e, 0x29, 0x66, 0x89, 0x58, 0xd8, 0x06, 0xc9, 0x2d, 0x80},
		std::vector<uint8_t>{0xf3, 0xc7, 0x50, 0xb7, 0x3c, 0xe2, 0xc6, 0x86, 0x87, 0x5e, 0x32, 0x32, 0x76, 0xa7, 0x41, 0xcf, 0xe7, 0xa4, 0xa4, 0x57, 0xaa, 0x25, 0x2f, 0x49, 0x0a, 0xf9, 0x7f, 0xca, 0x06, 0x91, 0x3b, 0xa6},
		std::vector<uint8_t>{0x4c, 0x37, 0x56, 0x11, 0xb4, 0xe5, 0xe4, 0x87, 0xa9, 0x29, 0x03, 0x87, 0x20, 0x2a, 0x14, 0x7f, 0x87, 0xbf, 0x70, 0xeb, 0x7c, 0x56, 0xf7, 0xed, 0x51, 0x3d, 0x90, 0x79, 0x96, 0x48, 0x3d, 0x57},
		std::vector<uint8_t>{0x90, 0x8a, 0x6b, 0xcc, 0xd5, 0xb4, 0xe8, 0x57, 0xe7, 0x7e, 0xad, 0x4e, 0xfc, 0xe2, 0xc0, 0x6c, 0xf1, 0xdd, 0x6f, 0xf1, 0x93, 0xb9, 0x1a, 0xf8, 0x18, 0xc0, 0x52, 0x94, 0x80, 0x4a, 0x8f, 0xcd},
		std::vector<uint8_t>{0x8c, 0x18, 0x23, 0x4a, 0x76, 0x2a, 0x22, 0xce, 0x37, 0x52, 0xa8, 0x26, 0xe4, 0xde, 0x7d, 0x13, 0xb3, 0x3f, 0x64, 0xd1, 0xe8, 0x74, 0x6b, 0x34, 0x12, 0xa1, 0x06, 0xb4, 0xcb, 0x41, 0xef, 0x00},
		std::vector<uint8_t>{0x73, 0xe5, 0x84, 0x67, 0x9d, 0x34, 0x1c, 0x7a, 0xe3, 0x37, 0x48, 0xf9, 0x56, 0x84, 0x16, 0xb8, 0xaa, 0x18, 0xfd, 0x83, 0x76, 0xe9, 0xcb, 0x39, 0xc0, 0x7b, 0x8a, 0xf6, 0xd5, 0x2a, 0xbc, 0x59},
		std::vector<uint8_t>{0xea, 0x58, 0xe8, 0xa7, 0x09, 0x10, 0xd3, 0x91, 0x76, 0x99, 0xf5, 0x39, 0xf8, 0x05, 0x06, 0xaa, 0x85, 0xc6, 0x3c, 0x9b, 0x99, 0x9f, 0x91, 0xd2, 0xc0, 0x17, 0xc6, 0xcb, 0x17, 0x77, 0x74, 0xf6},
		std::vector<uint8_t>{0x51, 0xb9, 0x39, 0xd3, 0xbc, 0xc7, 0x93, 0x72, 0x6f, 0xdf, 0x90, 0x4e, 0x85, 0x4a, 0x07, 0x20, 0x5b, 0xae, 0xe9, 0x30, 0x9a, 0xe0, 0xf8, 0xc9, 0x89, 0xc0, 0xcd, 0x30, 0x11, 0x24, 0x7b, 0x93}
	}};

	std::array<std::vector<uint8_t>,  c255_patternsSize> c255_messages = {{
		std::vector<uint8_t>{},
		std::vector<uint8_t>{0x03},
		std::vector<uint8_t>{0x0c, 0x3e, 0x54, 0x40, 0x74, 0xec, 0x63, 0xb0, 0x26, 0x5e, 0x0c},
		std::vector<uint8_t>{0x64, 0xa6, 0x5f, 0x3c, 0xde, 0xdc, 0xdd, 0x66, 0x81, 0x1e, 0x29, 0x15},
		std::vector<uint8_t>{0x64, 0xa6, 0x5f, 0x3c, 0xde, 0xdc, 0xdd, 0x66, 0x81, 0x1e, 0x29, 0x15, 0xe7},
		std::vector<uint8_t>{0xbd, 0x0f, 0x6a, 0x37, 0x47, 0xcd, 0x56, 0x1b, 0xdd, 0xdf, 0x46, 0x40, 0xa3, 0x32, 0x46, 0x1a, 0x4a, 0x30, 0xa1, 0x2a, 0x43, 0x4c, 0xd0, 0xbf, 0x40, 0xd7, 0x66, 0xd9, 0xc6, 0xd4, 0x58, 0xe5, 0x51, 0x22, 0x04, 0xa3, 0x0c, 0x17, 0xd1, 0xf5, 0x0b, 0x50, 0x79, 0x63, 0x1f, 0x64, 0xeb, 0x31, 0x12, 0x18, 0x2d, 0xa3, 0x00, 0x58, 0x35, 0x46, 0x11, 0x13, 0x71, 0x8d, 0x1a, 0x5e, 0xf9, 0x44},
		std::vector<uint8_t>{0x15, 0x77, 0x75, 0x32, 0xb0, 0xbd, 0xd0, 0xd1, 0x38, 0x9f, 0x63, 0x6c, 0x5f, 0x6b, 0x9b, 0xa7, 0x34, 0xc9, 0x0a, 0xf5, 0x72, 0x87, 0x7e, 0x2d, 0x27, 0x2d, 0xd0, 0x78, 0xaa, 0x1e, 0x56, 0x7c, 0xfa, 0x80, 0xe1, 0x29, 0x28, 0xbb, 0x54, 0x23, 0x30, 0xe8, 0x40, 0x9f, 0x31, 0x74, 0x50, 0x41, 0x07, 0xec, 0xd5, 0xef, 0xac, 0x61, 0xae, 0x75, 0x04, 0xda, 0xbe, 0x2a, 0x60, 0x2e, 0xde, 0x89, 0xe5, 0xcc, 0xa6, 0x25, 0x7a, 0x7c, 0x77, 0xe2, 0x7a, 0x70, 0x2b, 0x3a, 0xe3, 0x9f, 0xc7, 0x69, 0xfc, 0x54, 0xf2, 0x39, 0x5a, 0xe6, 0xa1, 0x17, 0x8c, 0xab, 0x47, 0x38, 0xe5, 0x43, 0x07, 0x2f, 0xc1, 0xc1, 0x77, 0xfe, 0x71, 0xe9, 0x2e, 0x25, 0xbf, 0x03, 0xe4, 0xec, 0xb7, 0x2f, 0x47, 0xb6, 0x4d, 0x04, 0x65, 0xaa, 0xea, 0x4c, 0x7f, 0xad, 0x37, 0x25, 0x36, 0xc8, 0xba, 0x51, 0x6a, 0x60, 0x39, 0xc3, 0xc2, 0xa3, 0x9f, 0x0e, 0x4d, 0x83, 0x2b, 0xe4, 0x32, 0xdf, 0xa9, 0xa7, 0x06, 0xa6, 0xe5, 0xc7, 0xe1, 0x9f, 0x39, 0x79, 0x64, 0xca, 0x42, 0x58, 0x00, 0x2f, 0x7c, 0x05, 0x41, 0xb5, 0x90, 0x31, 0x6d, 0xbc, 0x56, 0x22, 0xb6, 0xb2, 0xa6, 0xfe, 0x7a, 0x4a, 0xbf, 0xfd, 0x96, 0x10, 0x5e, 0xca, 0x76, 0xea, 0x7b, 0x98, 0x81, 0x6a, 0xf0, 0x74, 0x8c, 0x10, 0xdf, 0x04, 0x8c, 0xe0, 0x12, 0xd9, 0x01, 0x01, 0x5a, 0x51, 0xf1, 0x89, 0xf3, 0x88, 0x81, 0x45, 0xc0, 0x36, 0x50, 0xaa, 0x23, 0xce, 0x89, 0x4c, 0x3b, 0xd8, 0x89, 0xe0, 0x30, 0xd5, 0x65, 0x07, 0x1c, 0x59, 0xf4, 0x09, 0xa9, 0x98, 0x1b, 0x51, 0x87, 0x8f, 0xd6, 0xfc, 0x11, 0x06, 0x24, 0xdc, 0xbc, 0xde, 0x0b, 0xf7, 0xa6, 0x9c, 0xcc, 0xe3, 0x8f, 0xab, 0xdf, 0x86, 0xf3, 0xbe, 0xf6, 0x04, 0x48, 0x19, 0xde, 0x11},
		std::vector<uint8_t>{0x54, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x73, 0x74, 0x20, 0x6f, 0x62, 0x76, 0x69, 0x6f, 0x75, 0x73, 0x20, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6d, 0x65, 0x6e, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x78, 0x70, 0x65, 0x72, 0x69, 0x6d, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x75, 0x74, 0x75, 0x61, 0x6c, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62, 0x79, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x62, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x73, 0x20, 0x73, 0x65, 0x74, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x77, 0x68, 0x69, 0x6c, 0x65, 0x20, 0x73, 0x74, 0x69, 0x6c, 0x6c, 0x20, 0x61, 0x74, 0x20, 0x61, 0x20, 0x73, 0x65, 0x6e, 0x73, 0x69, 0x62, 0x6c, 0x65, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x66, 0x72, 0x6f, 0x6d, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x73, 0x74, 0x65, 0x70, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x72, 0x65, 0x66, 0x6f, 0x72, 0x65, 0x2c, 0x20, 0x69, 0x6e, 0x20, 0x72, 0x65, 0x64, 0x75, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6d, 0x65, 0x6e, 0x61, 0x20, 0x69, 0x6e, 0x74, 0x6f, 0x20, 0x73, 0x63, 0x69, 0x65, 0x6e, 0x74, 0x69, 0x66, 0x69, 0x63, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x2c, 0x20, 0x69, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x73, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x69, 0x74, 0x75, 0x64, 0x65, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x69, 0x72, 0x65, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x68, 0x65, 0x6e, 0x20, 0x69, 0x74, 0x20, 0x69, 0x73, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x20, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x61, 0x20, 0x63, 0x65, 0x72, 0x74, 0x61, 0x69, 0x6e, 0x20, 0x77, 0x61, 0x79, 0x20, 0x75, 0x70, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x69, 0x63, 0x20, 0x6f, 0x72, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x69, 0x74, 0x20, 0x73, 0x65, 0x65, 0x6d, 0x73, 0x20, 0x61, 0x74, 0x20, 0x66, 0x69, 0x72, 0x73, 0x74, 0x20, 0x73, 0x69, 0x67, 0x68, 0x74, 0x20, 0x6e, 0x61, 0x74, 0x75, 0x72, 0x61, 0x6c, 0x20, 0x74, 0x6f, 0x20, 0x65, 0x78, 0x70, 0x6c, 0x61, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x61, 0x63, 0x74, 0x73, 0x20, 0x62, 0x79, 0x20, 0x61, 0x73, 0x73, 0x75, 0x6d, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x6f, 0x6d, 0x65, 0x74, 0x68, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x69, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x74, 0x20, 0x72, 0x65, 0x73, 0x74, 0x20, 0x6f, 0x72, 0x20, 0x69, 0x6e, 0x20, 0x6d, 0x6f, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x61, 0x63, 0x68, 0x20, 0x62, 0x6f, 0x64, 0x79, 0x2c, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x74, 0x69, 0x74, 0x75, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x69, 0x74, 0x73, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x69, 0x63, 0x20, 0x6f, 0x72, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x20, 0x73, 0x74, 0x61, 0x74, 0x65, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x63, 0x61, 0x70, 0x61, 0x62, 0x6c, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x74, 0x20, 0x61, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x61, 0x63, 0x63, 0x6f, 0x72, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x74, 0x6f, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x6c, 0x61, 0x77, 0x73, 0x2e, 0x49, 0x6e, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x77, 0x61, 0x79, 0x20, 0x6d, 0x61, 0x74, 0x68, 0x65, 0x6d, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x74, 0x68, 0x65, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x69, 0x63, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x6f, 0x66, 0x20, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x73, 0x6d, 0x2c, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x65, 0x63, 0x68, 0x61, 0x6e, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x75, 0x63, 0x74, 0x6f, 0x72, 0x73, 0x20, 0x63, 0x61, 0x72, 0x72, 0x79, 0x69, 0x6e, 0x67, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x69, 0x6e, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x73, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x62, 0x65, 0x65, 0x6e, 0x20, 0x66, 0x6f, 0x72, 0x6d, 0x65, 0x64, 0x2e, 0x20, 0x49, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x74, 0x77, 0x6f, 0x20, 0x62, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x20, 0x69, 0x73, 0x20, 0x74, 0x72, 0x65, 0x61, 0x74, 0x65, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x72, 0x65, 0x66, 0x65, 0x72, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x6e, 0x6c, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x63, 0x6f, 0x6e, 0x64, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x62, 0x6f, 0x64, 0x69, 0x65, 0x73, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x70, 0x6f, 0x73, 0x69, 0x74, 0x69, 0x6f, 0x6e, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x69, 0x74, 0x68, 0x6f, 0x75, 0x74, 0x20, 0x61, 0x6e, 0x79, 0x20, 0x65, 0x78, 0x70, 0x72, 0x65, 0x73, 0x73, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x64, 0x65, 0x72, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x75, 0x72, 0x72, 0x6f, 0x75, 0x6e, 0x64, 0x69, 0x6e, 0x67, 0x20, 0x6d, 0x65, 0x64, 0x69, 0x75, 0x6d, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x73, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6f, 0x72, 0x69, 0x65, 0x73, 0x20, 0x61, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x2c, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x6f, 0x72, 0x20, 0x6c, 0x65, 0x73, 0x73, 0x20, 0x65, 0x78, 0x70, 0x6c, 0x69, 0x63, 0x69, 0x74, 0x6c, 0x79, 0x2c, 0x20, 0x74, 0x68, 0x65, 0x20, 0x65, 0x78, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x63, 0x65, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x75, 0x62, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x73, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x77, 0x68, 0x69, 0x63, 0x68, 0x20, 0x68, 0x61, 0x76, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x6f, 0x70, 0x65, 0x72, 0x74, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x63, 0x74, 0x69, 0x6e, 0x67, 0x20, 0x6f, 0x6e, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x61, 0x6e, 0x6f, 0x74, 0x68, 0x65, 0x72, 0x20, 0x61, 0x74, 0x20, 0x61, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x62, 0x79, 0x20, 0x61, 0x74, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x72, 0x20, 0x72, 0x65, 0x70, 0x75, 0x6c, 0x73, 0x69, 0x6f, 0x6e, 0x2e, 0x20, 0x54, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x73, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x6c, 0x65, 0x74, 0x65, 0x20, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x6d, 0x65, 0x6e, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x61, 0x20, 0x74, 0x68, 0x65, 0x6f, 0x72, 0x79, 0x20, 0x6f, 0x66, 0x20, 0x74, 0x68, 0x69, 0x73, 0x20, 0x6b, 0x69, 0x6e, 0x64, 0x20, 0x69, 0x73, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x4d, 0x2e, 0x57, 0x2e, 0x20, 0x57, 0x65, 0x62, 0x65, 0x72, 0x5b, 0x31, 0x5d, 0x2c, 0x20, 0x77, 0x68, 0x6f, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x61, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x65, 0x6f, 0x72, 0x79, 0x20, 0x69, 0x6e, 0x63, 0x6c, 0x75, 0x64, 0x65, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x6f, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x6f, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x20, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6d, 0x65, 0x6e, 0x61, 0x2e, 0x20, 0x49, 0x6e, 0x20, 0x64, 0x6f, 0x69, 0x6e, 0x67, 0x20, 0x73, 0x6f, 0x2c, 0x20, 0x68, 0x6f, 0x77, 0x65, 0x76, 0x65, 0x72, 0x2c, 0x20, 0x68, 0x65, 0x20, 0x68, 0x61, 0x73, 0x20, 0x66, 0x6f, 0x75, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x6e, 0x65, 0x63, 0x65, 0x73, 0x73, 0x61, 0x72, 0x79, 0x20, 0x74, 0x6f, 0x20, 0x61, 0x73, 0x73, 0x75, 0x6d, 0x65, 0x20, 0x74, 0x68, 0x61, 0x74, 0x20, 0x74, 0x68, 0x65, 0x20, 0x66, 0x6f, 0x72, 0x63, 0x65, 0x20, 0x62, 0x65, 0x74, 0x77, 0x65, 0x65, 0x6e, 0x20, 0x74, 0x77, 0x6f, 0x20, 0x70, 0x61, 0x72, 0x74, 0x69, 0x63, 0x6c, 0x65, 0x73, 0x20, 0x64, 0x65, 0x70, 0x65, 0x6e, 0x64, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x72, 0x65, 0x6c, 0x61, 0x74, 0x69, 0x76, 0x65, 0x20, 0x76, 0x65, 0x6c, 0x6f, 0x63, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x77, 0x65, 0x6c, 0x6c, 0x20, 0x61, 0x73, 0x20, 0x6f, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x69, 0x72, 0x20, 0x64, 0x69, 0x73, 0x74, 0x61, 0x6e, 0x63, 0x65, 0x2e, 0x20, 0x54, 0x68, 0x69, 0x73, 0x20, 0x74, 0x68, 0x65, 0x6f, 0x72, 0x79, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x64, 0x65, 0x76, 0x65, 0x6c, 0x6f, 0x70, 0x65, 0x64, 0x20, 0x62, 0x79, 0x20, 0x4d, 0x4d, 0x2e, 0x20, 0x57, 0x2e, 0x20, 0x57, 0x65, 0x62, 0x65, 0x72, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x43, 0x2e, 0x20, 0x4e, 0x65, 0x75, 0x6d, 0x61, 0x6e, 0x6e, 0x5b, 0x32, 0x5d, 0x2c, 0x20, 0x69, 0x73, 0x20, 0x65, 0x78, 0x63, 0x65, 0x65, 0x64, 0x69, 0x6e, 0x67, 0x6c, 0x79, 0x20, 0x69, 0x6e, 0x67, 0x65, 0x6e, 0x69, 0x6f, 0x75, 0x73, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x77, 0x6f, 0x6e, 0x64, 0x65, 0x72, 0x66, 0x75, 0x6c, 0x6c, 0x79, 0x20, 0x63, 0x6f, 0x6d, 0x70, 0x72, 0x65, 0x68, 0x65, 0x6e, 0x73, 0x69, 0x76, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x69, 0x74, 0x73, 0x20, 0x61, 0x70, 0x70, 0x6c, 0x69, 0x63, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x74, 0x6f, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6d, 0x65, 0x6e, 0x61, 0x20, 0x6f, 0x66, 0x20, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x69, 0x63, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x6f, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x20, 0x61, 0x74, 0x74, 0x72, 0x61, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x2c, 0x20, 0x69, 0x6e, 0x64, 0x75, 0x63, 0x74, 0x69, 0x6f, 0x6e, 0x20, 0x6f, 0x66, 0x20, 0x63, 0x75, 0x72, 0x72, 0x65, 0x6e, 0x74, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x64, 0x69, 0x61, 0x6d, 0x61, 0x67, 0x6e, 0x65, 0x74, 0x69, 0x63, 0x20, 0x70, 0x68, 0x65, 0x6e, 0x6f, 0x6d, 0x65, 0x6e, 0x61, 0x3b, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x69, 0x74, 0x20, 0x63, 0x6f, 0x6d, 0x65, 0x73, 0x20, 0x74, 0x6f, 0x20, 0x75, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x74, 0x68, 0x65, 0x20, 0x6d, 0x6f, 0x72, 0x65, 0x20, 0x61, 0x75, 0x74, 0x68, 0x6f, 0x72, 0x69, 0x74, 0x79, 0x2c, 0x20, 0x61, 0x73, 0x20, 0x69, 0x74, 0x20, 0x68, 0x61, 0x73, 0x20, 0x73, 0x65, 0x72, 0x76, 0x65, 0x64, 0x20, 0x74, 0x6f, 0x20, 0x67, 0x75, 0x69, 0x64, 0x65, 0x20, 0x74, 0x68, 0x65, 0x20, 0x73, 0x70, 0x65, 0x63, 0x75, 0x6c, 0x61, 0x74, 0x69, 0x6f, 0x6e, 0x73, 0x20, 0x6f, 0x66, 0x20, 0x6f, 0x6e, 0x65, 0x20, 0x77, 0x68, 0x6f, 0x20, 0x68, 0x61, 0x73, 0x20, 0x6d, 0x61, 0x64, 0x65, 0x20, 0x73, 0x6f, 0x20, 0x67, 0x72, 0x65, 0x61, 0x74, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x64, 0x76, 0x61, 0x6e, 0x63, 0x65, 0x20, 0x69, 0x6e, 0x20, 0x74, 0x68, 0x65, 0x20, 0x70, 0x72, 0x61, 0x63, 0x74, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x70, 0x61, 0x72, 0x74, 0x20, 0x6f, 0x66, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x69, 0x63, 0x20, 0x73, 0x63, 0x69, 0x65, 0x6e, 0x63, 0x65, 0x2c, 0x20, 0x62, 0x6f, 0x74, 0x68, 0x20, 0x62, 0x79, 0x20, 0x69, 0x6e, 0x74, 0x72, 0x6f, 0x64, 0x75, 0x63, 0x69, 0x6e, 0x67, 0x20, 0x61, 0x20, 0x63, 0x6f, 0x6e, 0x73, 0x69, 0x73, 0x74, 0x65, 0x6e, 0x74, 0x20, 0x73, 0x79, 0x73, 0x74, 0x65, 0x6d, 0x20, 0x6f, 0x66, 0x20, 0x75, 0x6e, 0x69, 0x74, 0x73, 0x20, 0x69, 0x6e, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x6d, 0x65, 0x61, 0x73, 0x75, 0x72, 0x65, 0x6d, 0x65, 0x6e, 0x74, 0x2c, 0x20, 0x61, 0x6e, 0x64, 0x20, 0x62, 0x79, 0x20, 0x61, 0x63, 0x74, 0x75, 0x61, 0x6c, 0x6c, 0x79, 0x20, 0x64, 0x65, 0x74, 0x65, 0x72, 0x6d, 0x69, 0x6e, 0x69, 0x6e, 0x67, 0x20, 0x65, 0x6c, 0x65, 0x63, 0x74, 0x72, 0x69, 0x63, 0x61, 0x6c, 0x20, 0x71, 0x75, 0x61, 0x6e, 0x74, 0x69, 0x74, 0x69, 0x65, 0x73, 0x20, 0x77, 0x69, 0x74, 0x68, 0x20, 0x61, 0x6e, 0x20, 0x61, 0x63, 0x63, 0x75, 0x72, 0x61, 0x63, 0x79, 0x20, 0x68, 0x69, 0x74, 0x68, 0x65, 0x72, 0x74, 0x6f, 0x20, 0x75, 0x6e, 0x6b, 0x6e, 0x6f, 0x77, 0x6e, 0x2e}
	}};

	std::array<std::vector<uint8_t>, c255_patternsSize> c255_signatures = {{
		std::vector<uint8_t>{0x78, 0x00, 0x4a, 0xfb, 0xc2, 0x80, 0xeb, 0x21, 0x77, 0xb2, 0xc5, 0x6a, 0x9f, 0xd4, 0x41, 0xfd, 0x32, 0xfa, 0xe1, 0x24, 0xf0, 0x5c, 0xb4, 0xf9, 0x8f, 0x17, 0x6f, 0x21, 0xc5, 0x16, 0xbb, 0x6a, 0xdf, 0xed, 0xac, 0x87, 0x37, 0xcf, 0xf4, 0x02, 0xc7, 0x0f, 0xec, 0xb1, 0xee, 0x24, 0x46, 0xc0, 0x55, 0xe2, 0x68, 0x57, 0x3d, 0x79, 0x39, 0x83, 0x8d, 0x1a, 0x5c, 0x9a, 0x71, 0x73, 0x95, 0x0f},
		std::vector<uint8_t>{0x5a, 0x06, 0x0f, 0xcd, 0x42, 0x9f, 0xe7, 0x71, 0x7d, 0xa7, 0xa4, 0x30, 0x22, 0xb8, 0x4c, 0xab, 0x63, 0xad, 0x9e, 0xd5, 0xf7, 0x50, 0x05, 0x57, 0xc2, 0x8f, 0xd7, 0xae, 0x84, 0xe1, 0x68, 0x9e, 0x45, 0x4a, 0x07, 0x45, 0x1d, 0x13, 0x69, 0x6f, 0xc0, 0xa7, 0xde, 0xd4, 0x8e, 0xe3, 0x34, 0x56, 0x2a, 0x17, 0xc6, 0x49, 0x52, 0x0d, 0x72, 0xba, 0x92, 0x59, 0xbe, 0x35, 0x6f, 0xe7, 0xf0, 0x0f},
		std::vector<uint8_t>{0x9c, 0x1a, 0x66, 0xbe, 0x4f, 0x1c, 0x2d, 0x07, 0xa5, 0xc0, 0x4c, 0x06, 0xca, 0x91, 0x8c, 0x5f, 0x35, 0x2c, 0x58, 0x7d, 0x07, 0x2f, 0x54, 0xa7, 0x14, 0x60, 0x79, 0xf4, 0x7f, 0xe8, 0x44, 0xe8, 0xdb, 0xe9, 0x6f, 0x7f, 0x02, 0x81, 0x9a, 0x28, 0x3f, 0x1d, 0x9a, 0x4b, 0xc2, 0xfe, 0xa0, 0x66, 0x46, 0x51, 0x02, 0xd7, 0x14, 0x11, 0x4f, 0x62, 0xaa, 0xed, 0x67, 0xce, 0xc1, 0x9b, 0x85, 0x07},
		std::vector<uint8_t>{0xb9, 0xa5, 0xdc, 0x2f, 0x99, 0xf0, 0x4b, 0xcc, 0xdb, 0xa9, 0xb6, 0x5c, 0x41, 0x25, 0x80, 0xe6, 0x00, 0x3e, 0x5b, 0xcb, 0x87, 0xb5, 0x4d, 0x1a, 0xf6, 0x41, 0xea, 0xbb, 0x09, 0xfd, 0x82, 0xb2, 0x16, 0xae, 0x05, 0x26, 0x27, 0x0b, 0xb7, 0x84, 0xf0, 0xd2, 0xcf, 0x89, 0x76, 0x8c, 0xb0, 0x45, 0x4e, 0x3e, 0x20, 0xf2, 0x2f, 0x33, 0x3b, 0x36, 0xd5, 0x44, 0x33, 0x6a, 0x34, 0xa9, 0xaf, 0x06},
		std::vector<uint8_t>{0x95, 0xf5, 0xca, 0x35, 0xd2, 0x9c, 0xdc, 0x23, 0x4d, 0x68, 0xf1, 0x13, 0xf3, 0xeb, 0xfc, 0x33, 0x5a, 0xb2, 0xfd, 0x90, 0x5d, 0x2c, 0x54, 0x75, 0x7a, 0xac, 0x6b, 0x3d, 0xa7, 0x3d, 0xbf, 0x4f, 0xbb, 0x64, 0x7e, 0xa4, 0x6e, 0x66, 0x58, 0x08, 0x81, 0x5f, 0x4d, 0xfb, 0xa7, 0x66, 0x58, 0xc4, 0x43, 0xc4, 0xb9, 0x58, 0xb4, 0x57, 0x0d, 0x27, 0xb5, 0xb6, 0x7e, 0x5c, 0x01, 0x0c, 0x1e, 0x0e},
		std::vector<uint8_t>{0xcc, 0x05, 0x1f, 0xc2, 0x25, 0x37, 0x09, 0x94, 0xda, 0x08, 0xc1, 0x20, 0xc2, 0x7b, 0x06, 0xa3, 0xef, 0x3c, 0x9f, 0x76, 0x2f, 0x69, 0xcc, 0x58, 0x40, 0x50, 0xbe, 0xc9, 0x4a, 0x56, 0xbb, 0x46, 0xc9, 0xf7, 0xad, 0x4c, 0x2f, 0xc5, 0x9f, 0xe0, 0x31, 0xed, 0x0c, 0x8b, 0x9a, 0x56, 0x1a, 0xe5, 0x23, 0x49, 0x6b, 0x0f, 0x1b, 0xd2, 0x33, 0x84, 0x3c, 0x1e, 0xbc, 0xb7, 0xc4, 0x1c, 0xdf, 0x0b},
		std::vector<uint8_t>{0xac, 0x83, 0x30, 0x89, 0x08, 0x13, 0xdd, 0x26, 0xb4, 0x7f, 0xb6, 0xef, 0x43, 0x04, 0xe5, 0x5a, 0xbd, 0x7d, 0x90, 0x3c, 0x82, 0x08, 0xad, 0x4e, 0x91, 0x16, 0xb8, 0xae, 0xc2, 0xbe, 0x33, 0x6e, 0x2d, 0x34, 0xf3, 0x17, 0xe1, 0xd3, 0xf6, 0x2a, 0x01, 0x11, 0xab, 0xe5, 0x09, 0xe7, 0x3f, 0x0e, 0x4e, 0x3d, 0x8f, 0x58, 0x3d, 0x4c, 0x46, 0x45, 0xe7, 0xc9, 0xd8, 0xa0, 0x5f, 0x5d, 0xff, 0x06},
		std::vector<uint8_t>{0x0b, 0xa4, 0x77, 0xa9, 0xb7, 0xea, 0x08, 0x73, 0x4d, 0x2d, 0xeb, 0xcd, 0x9b, 0xa0, 0xbe, 0x78, 0x9a, 0x1a, 0xb4, 0xaf, 0x2f, 0xab, 0xe5, 0x31, 0x86, 0x30, 0x38, 0xfa, 0x2b, 0x12, 0x03, 0xa6, 0xd7, 0x07, 0x4c, 0x3e, 0xc2, 0x84, 0xfb, 0xfd, 0x26, 0x32, 0x46, 0xb6, 0xc9, 0xc8, 0xf9, 0x97, 0x5f, 0xa5, 0x92, 0x16, 0xc3, 0xd4, 0x7a, 0xe0, 0x74, 0x19, 0x7b, 0x99, 0x71, 0xff, 0x46, 0x0a}
	}};

	for (size_t i=0; i<c255_messages.size(); i++) {
		auto Alice = make_Signature<C255>();
		Alice->set_secret(DSA<C255, lime::DSAtype::privateKey> (c255_secret_keys[i].cbegin()));

		Alice->derivePublic();
		BC_ASSERT_TRUE(memcmp(Alice->get_public().data(), c255_public_keys[i].data(), c255_public_keys[i].size())==0);
		DSA<C255, lime::DSAtype::signature> signature{};
		Alice->sign(c255_messages[i], signature);
		BC_ASSERT_TRUE(memcmp(signature.data(), c255_signatures[i].data(), c255_signatures[i].size())==0);

		auto Vera = make_Signature<C255>();
		Vera->set_public(DSA<C255, lime::DSAtype::publicKey>(c255_public_keys[i].cbegin()));
		BC_ASSERT_TRUE(Vera->verify(c255_messages[i], signature));
	}

#endif
#ifdef EC448_ENABLED
	signAndVerify_test<C448>();
	if (bench) {
		LIME_LOGI<<"Bench for Curve 448:"<<endl;
		signAndVerify_bench<C448>(BENCH_TIMING_MS);
	}

	/* pattern from RFC 8032 */
	constexpr size_t c448_patternsSize = 8;
	std::array<std::vector<uint8_t>, c448_patternsSize> c448_secret_keys = {{
		std::vector<uint8_t>{0x6c, 0x82, 0xa5, 0x62, 0xcb, 0x80, 0x8d, 0x10, 0xd6, 0x32, 0xbe, 0x89, 0xc8, 0x51, 0x3e, 0xbf, 0x6c, 0x92, 0x9f, 0x34, 0xdd, 0xfa, 0x8c, 0x9f, 0x63, 0xc9, 0x96, 0x0e, 0xf6, 0xe3, 0x48, 0xa3, 0x52, 0x8c, 0x8a, 0x3f, 0xcc, 0x2f, 0x04, 0x4e, 0x39, 0xa3, 0xfc, 0x5b, 0x94, 0x49, 0x2f, 0x8f, 0x03, 0x2e, 0x75, 0x49, 0xa2, 0x00, 0x98, 0xf9, 0x5b}, 
		std::vector<uint8_t>{0xc4, 0xea, 0xb0, 0x5d, 0x35, 0x70, 0x07, 0xc6, 0x32, 0xf3, 0xdb, 0xb4, 0x84, 0x89, 0x92, 0x4d, 0x55, 0x2b, 0x08, 0xfe, 0x0c, 0x35, 0x3a, 0x0d, 0x4a, 0x1f, 0x00, 0xac, 0xda, 0x2c, 0x46, 0x3a, 0xfb, 0xea, 0x67, 0xc5, 0xe8, 0xd2, 0x87, 0x7c, 0x5e, 0x3b, 0xc3, 0x97, 0xa6, 0x59, 0x94, 0x9e, 0xf8, 0x02, 0x1e, 0x95, 0x4e, 0x0a, 0x12, 0x27, 0x4e},
		std::vector<uint8_t>{0xcd, 0x23, 0xd2, 0x4f, 0x71, 0x42, 0x74, 0xe7, 0x44, 0x34, 0x32, 0x37, 0xb9, 0x32, 0x90, 0xf5, 0x11, 0xf6, 0x42, 0x5f, 0x98, 0xe6, 0x44, 0x59, 0xff, 0x20, 0x3e, 0x89, 0x85, 0x08, 0x3f, 0xfd, 0xf6, 0x05, 0x00, 0x55, 0x3a, 0xbc, 0x0e, 0x05, 0xcd, 0x02, 0x18, 0x4b, 0xdb, 0x89, 0xc4, 0xcc, 0xd6, 0x7e, 0x18, 0x79, 0x51, 0x26, 0x7e, 0xb3, 0x28},
		std::vector<uint8_t>{0x25, 0x8c, 0xdd, 0x4a, 0xda, 0x32, 0xed, 0x9c, 0x9f, 0xf5, 0x4e, 0x63, 0x75, 0x6a, 0xe5, 0x82, 0xfb, 0x8f, 0xab, 0x2a, 0xc7, 0x21, 0xf2, 0xc8, 0xe6, 0x76, 0xa7, 0x27, 0x68, 0x51, 0x3d, 0x93, 0x9f, 0x63, 0xdd, 0xdb, 0x55, 0x60, 0x91, 0x33, 0xf2, 0x9a, 0xdf, 0x86, 0xec, 0x99, 0x29, 0xdc, 0xcb, 0x52, 0xc1, 0xc5, 0xfd, 0x2f, 0xf7, 0xe2, 0x1b},
		std::vector<uint8_t>{0x7e, 0xf4, 0xe8, 0x45, 0x44, 0x23, 0x67, 0x52, 0xfb, 0xb5, 0x6b, 0x8f, 0x31, 0xa2, 0x3a, 0x10, 0xe4, 0x28, 0x14, 0xf5, 0xf5, 0x5c, 0xa0, 0x37, 0xcd, 0xcc, 0x11, 0xc6, 0x4c, 0x9a, 0x3b, 0x29, 0x49, 0xc1, 0xbb, 0x60, 0x70, 0x03, 0x14, 0x61, 0x17, 0x32, 0xa6, 0xc2, 0xfe, 0xa9, 0x8e, 0xeb, 0xc0, 0x26, 0x6a, 0x11, 0xa9, 0x39, 0x70, 0x10, 0x0e},
		std::vector<uint8_t>{0xd6, 0x5d, 0xf3, 0x41, 0xad, 0x13, 0xe0, 0x08, 0x56, 0x76, 0x88, 0xba, 0xed, 0xda, 0x8e, 0x9d, 0xcd, 0xc1, 0x7d, 0xc0, 0x24, 0x97, 0x4e, 0xa5, 0xb4, 0x22, 0x7b, 0x65, 0x30, 0xe3, 0x39, 0xbf, 0xf2, 0x1f, 0x99, 0xe6, 0x8c, 0xa6, 0x96, 0x8f, 0x3c, 0xca, 0x6d, 0xfe, 0x0f, 0xb9, 0xf4, 0xfa, 0xb4, 0xfa, 0x13, 0x5d, 0x55, 0x42, 0xea, 0x3f, 0x01},
		std::vector<uint8_t>{0x2e, 0xc5, 0xfe, 0x3c, 0x17, 0x04, 0x5a, 0xbd, 0xb1, 0x36, 0xa5, 0xe6, 0xa9, 0x13, 0xe3, 0x2a, 0xb7, 0x5a, 0xe6, 0x8b, 0x53, 0xd2, 0xfc, 0x14, 0x9b, 0x77, 0xe5, 0x04, 0x13, 0x2d, 0x37, 0x56, 0x9b, 0x7e, 0x76, 0x6b, 0xa7, 0x4a, 0x19, 0xbd, 0x61, 0x62, 0x34, 0x3a, 0x21, 0xc8, 0x59, 0x0a, 0xa9, 0xce, 0xbc, 0xa9, 0x01, 0x4c, 0x63, 0x6d, 0xf5},
		std::vector<uint8_t>{0x87, 0x2d, 0x09, 0x37, 0x80, 0xf5, 0xd3, 0x73, 0x0d, 0xf7, 0xc2, 0x12, 0x66, 0x4b, 0x37, 0xb8, 0xa0, 0xf2, 0x4f, 0x56, 0x81, 0x0d, 0xaa, 0x83, 0x82, 0xcd, 0x4f, 0xa3, 0xf7, 0x76, 0x34, 0xec, 0x44, 0xdc, 0x54, 0xf1, 0xc2, 0xed, 0x9b, 0xea, 0x86, 0xfa, 0xfb, 0x76, 0x32, 0xd8, 0xbe, 0x19, 0x9e, 0xa1, 0x65, 0xf5, 0xad, 0x55, 0xdd, 0x9c, 0xe8}
	}};

	std::array<std::vector<uint8_t>, c448_patternsSize> c448_public_keys = {{
		std::vector<uint8_t>{0x5f, 0xd7, 0x44, 0x9b, 0x59, 0xb4, 0x61, 0xfd, 0x2c, 0xe7, 0x87, 0xec, 0x61, 0x6a, 0xd4, 0x6a, 0x1d, 0xa1, 0x34, 0x24, 0x85, 0xa7, 0x0e, 0x1f, 0x8a, 0x0e, 0xa7, 0x5d, 0x80, 0xe9, 0x67, 0x78, 0xed, 0xf1, 0x24, 0x76, 0x9b, 0x46, 0xc7, 0x06, 0x1b, 0xd6, 0x78, 0x3d, 0xf1, 0xe5, 0x0f, 0x6c, 0xd1, 0xfa, 0x1a, 0xbe, 0xaf, 0xe8, 0x25, 0x61, 0x80},
		std::vector<uint8_t>{0x43, 0xba, 0x28, 0xf4, 0x30, 0xcd, 0xff, 0x45, 0x6a, 0xe5, 0x31, 0x54, 0x5f, 0x7e, 0xcd, 0x0a, 0xc8, 0x34, 0xa5, 0x5d, 0x93, 0x58, 0xc0, 0x37, 0x2b, 0xfa, 0x0c, 0x6c, 0x67, 0x98, 0xc0, 0x86, 0x6a, 0xea, 0x01, 0xeb, 0x00, 0x74, 0x28, 0x02, 0xb8, 0x43, 0x8e, 0xa4, 0xcb, 0x82, 0x16, 0x9c, 0x23, 0x51, 0x60, 0x62, 0x7b, 0x4c, 0x3a, 0x94, 0x80},
		std::vector<uint8_t>{0xdc, 0xea, 0x9e, 0x78, 0xf3, 0x5a, 0x1b, 0xf3, 0x49, 0x9a, 0x83, 0x1b, 0x10, 0xb8, 0x6c, 0x90, 0xaa, 0xc0, 0x1c, 0xd8, 0x4b, 0x67, 0xa0, 0x10, 0x9b, 0x55, 0xa3, 0x6e, 0x93, 0x28, 0xb1, 0xe3, 0x65, 0xfc, 0xe1, 0x61, 0xd7, 0x1c, 0xe7, 0x13, 0x1a, 0x54, 0x3e, 0xa4, 0xcb, 0x5f, 0x7e, 0x9f, 0x1d, 0x8b, 0x00, 0x69, 0x64, 0x47, 0x00, 0x14, 0x00},
		std::vector<uint8_t>{0x3b, 0xa1, 0x6d, 0xa0, 0xc6, 0xf2, 0xcc, 0x1f, 0x30, 0x18, 0x77, 0x40, 0x75, 0x6f, 0x5e, 0x79, 0x8d, 0x6b, 0xc5, 0xfc, 0x01, 0x5d, 0x7c, 0x63, 0xcc, 0x95, 0x10, 0xee, 0x3f, 0xd4, 0x4a, 0xdc, 0x24, 0xd8, 0xe9, 0x68, 0xb6, 0xe4, 0x6e, 0x6f, 0x94, 0xd1, 0x9b, 0x94, 0x53, 0x61, 0x72, 0x6b, 0xd7, 0x5e, 0x14, 0x9e, 0xf0, 0x98, 0x17, 0xf5, 0x80},
		std::vector<uint8_t>{0xb3, 0xda, 0x07, 0x9b, 0x0a, 0xa4, 0x93, 0xa5, 0x77, 0x20, 0x29, 0xf0, 0x46, 0x7b, 0xae, 0xbe, 0xe5, 0xa8, 0x11, 0x2d, 0x9d, 0x3a, 0x22, 0x53, 0x23, 0x61, 0xda, 0x29, 0x4f, 0x7b, 0xb3, 0x81, 0x5c, 0x5d, 0xc5, 0x9e, 0x17, 0x6b, 0x4d, 0x9f, 0x38, 0x1c, 0xa0, 0x93, 0x8e, 0x13, 0xc6, 0xc0, 0x7b, 0x17, 0x4b, 0xe6, 0x5d, 0xfa, 0x57, 0x8e, 0x80},
		std::vector<uint8_t>{0xdf, 0x97, 0x05, 0xf5, 0x8e, 0xdb, 0xab, 0x80, 0x2c, 0x7f, 0x83, 0x63, 0xcf, 0xe5, 0x56, 0x0a, 0xb1, 0xc6, 0x13, 0x2c, 0x20, 0xa9, 0xf1, 0xdd, 0x16, 0x34, 0x83, 0xa2, 0x6f, 0x8a, 0xc5, 0x3a, 0x39, 0xd6, 0x80, 0x8b, 0xf4, 0xa1, 0xdf, 0xbd, 0x26, 0x1b, 0x09, 0x9b, 0xb0, 0x3b, 0x3f, 0xb5, 0x09, 0x06, 0xcb, 0x28, 0xbd, 0x8a, 0x08, 0x1f, 0x00},
		std::vector<uint8_t>{0x79, 0x75, 0x6f, 0x01, 0x4d, 0xcf, 0xe2, 0x07, 0x9f, 0x5d, 0xd9, 0xe7, 0x18, 0xbe, 0x41, 0x71, 0xe2, 0xef, 0x24, 0x86, 0xa0, 0x8f, 0x25, 0x18, 0x6f, 0x6b, 0xff, 0x43, 0xa9, 0x93, 0x6b, 0x9b, 0xfe, 0x12, 0x40, 0x2b, 0x08, 0xae, 0x65, 0x79, 0x8a, 0x3d, 0x81, 0xe2, 0x2e, 0x9e, 0xc8, 0x0e, 0x76, 0x90, 0x86, 0x2e, 0xf3, 0xd4, 0xed, 0x3a, 0x00},
		std::vector<uint8_t>{0xa8, 0x1b, 0x2e, 0x8a, 0x70, 0xa5, 0xac, 0x94, 0xff, 0xdb, 0xcc, 0x9b, 0xad, 0xfc, 0x3f, 0xeb, 0x08, 0x01, 0xf2, 0x58, 0x57, 0x8b, 0xb1, 0x14, 0xad, 0x44, 0xec, 0xe1, 0xec, 0x0e, 0x79, 0x9d, 0xa0, 0x8e, 0xff, 0xb8, 0x1c, 0x5d, 0x68, 0x5c, 0x0c, 0x56, 0xf6, 0x4e, 0xec, 0xae, 0xf8, 0xcd, 0xf1, 0x1c, 0xc3, 0x87, 0x37, 0x83, 0x8c, 0xf4, 0x00}
	}};

	std::array<std::vector<uint8_t>,  c448_patternsSize> c448_messages = {{
		std::vector<uint8_t>{},
		std::vector<uint8_t>{0x03},
		std::vector<uint8_t>{0x0c, 0x3e, 0x54, 0x40, 0x74, 0xec, 0x63, 0xb0, 0x26, 0x5e, 0x0c, },
		std::vector<uint8_t>{0x64, 0xa6, 0x5f, 0x3c, 0xde, 0xdc, 0xdd, 0x66, 0x81, 0x1e, 0x29, 0x15},
		std::vector<uint8_t>{0x64, 0xa6, 0x5f, 0x3c, 0xde, 0xdc, 0xdd, 0x66, 0x81, 0x1e, 0x29, 0x15, 0xe7},
		std::vector<uint8_t>{0xbd, 0x0f, 0x6a, 0x37, 0x47, 0xcd, 0x56, 0x1b, 0xdd, 0xdf, 0x46, 0x40, 0xa3, 0x32, 0x46, 0x1a, 0x4a, 0x30, 0xa1, 0x2a, 0x43, 0x4c, 0xd0, 0xbf, 0x40, 0xd7, 0x66, 0xd9, 0xc6, 0xd4, 0x58, 0xe5, 0x51, 0x22, 0x04, 0xa3, 0x0c, 0x17, 0xd1, 0xf5, 0x0b, 0x50, 0x79, 0x63, 0x1f, 0x64, 0xeb, 0x31, 0x12, 0x18, 0x2d, 0xa3, 0x00, 0x58, 0x35, 0x46, 0x11, 0x13, 0x71, 0x8d, 0x1a, 0x5e, 0xf9, 0x44},
		std::vector<uint8_t>{0x15, 0x77, 0x75, 0x32, 0xb0, 0xbd, 0xd0, 0xd1, 0x38, 0x9f, 0x63, 0x6c, 0x5f, 0x6b, 0x9b, 0xa7, 0x34, 0xc9, 0x0a, 0xf5, 0x72, 0x87, 0x7e, 0x2d, 0x27, 0x2d, 0xd0, 0x78, 0xaa, 0x1e, 0x56, 0x7c, 0xfa, 0x80, 0xe1, 0x29, 0x28, 0xbb, 0x54, 0x23, 0x30, 0xe8, 0x40, 0x9f, 0x31, 0x74, 0x50, 0x41, 0x07, 0xec, 0xd5, 0xef, 0xac, 0x61, 0xae, 0x75, 0x04, 0xda, 0xbe, 0x2a, 0x60, 0x2e, 0xde, 0x89, 0xe5, 0xcc, 0xa6, 0x25, 0x7a, 0x7c, 0x77, 0xe2, 0x7a, 0x70, 0x2b, 0x3a, 0xe3, 0x9f, 0xc7, 0x69, 0xfc, 0x54, 0xf2, 0x39, 0x5a, 0xe6, 0xa1, 0x17, 0x8c, 0xab, 0x47, 0x38, 0xe5, 0x43, 0x07, 0x2f, 0xc1, 0xc1, 0x77, 0xfe, 0x71, 0xe9, 0x2e, 0x25, 0xbf, 0x03, 0xe4, 0xec, 0xb7, 0x2f, 0x47, 0xb6, 0x4d, 0x04, 0x65, 0xaa, 0xea, 0x4c, 0x7f, 0xad, 0x37, 0x25, 0x36, 0xc8, 0xba, 0x51, 0x6a, 0x60, 0x39, 0xc3, 0xc2, 0xa3, 0x9f, 0x0e, 0x4d, 0x83, 0x2b, 0xe4, 0x32, 0xdf, 0xa9, 0xa7, 0x06, 0xa6, 0xe5, 0xc7, 0xe1, 0x9f, 0x39, 0x79, 0x64, 0xca, 0x42, 0x58, 0x00, 0x2f, 0x7c, 0x05, 0x41, 0xb5, 0x90, 0x31, 0x6d, 0xbc, 0x56, 0x22, 0xb6, 0xb2, 0xa6, 0xfe, 0x7a, 0x4a, 0xbf, 0xfd, 0x96, 0x10, 0x5e, 0xca, 0x76, 0xea, 0x7b, 0x98, 0x81, 0x6a, 0xf0, 0x74, 0x8c, 0x10, 0xdf, 0x04, 0x8c, 0xe0, 0x12, 0xd9, 0x01, 0x01, 0x5a, 0x51, 0xf1, 0x89, 0xf3, 0x88, 0x81, 0x45, 0xc0, 0x36, 0x50, 0xaa, 0x23, 0xce, 0x89, 0x4c, 0x3b, 0xd8, 0x89, 0xe0, 0x30, 0xd5, 0x65, 0x07, 0x1c, 0x59, 0xf4, 0x09, 0xa9, 0x98, 0x1b, 0x51, 0x87, 0x8f, 0xd6, 0xfc, 0x11, 0x06, 0x24, 0xdc, 0xbc, 0xde, 0x0b, 0xf7, 0xa6, 0x9c, 0xcc, 0xe3, 0x8f, 0xab, 0xdf, 0x86, 0xf3, 0xbe, 0xf6, 0x04, 0x48, 0x19, 0xde, 0x11},
		std::vector<uint8_t>{0x6d, 0xdf, 0x80, 0x2e, 0x1a, 0xae, 0x49, 0x86, 0x93, 0x5f, 0x7f, 0x98, 0x1b, 0xa3, 0xf0, 0x35, 0x1d, 0x62, 0x73, 0xc0, 0xa0, 0xc2, 0x2c, 0x9c, 0x0e, 0x83, 0x39, 0x16, 0x8e, 0x67, 0x54, 0x12, 0xa3, 0xde, 0xbf, 0xaf, 0x43, 0x5e, 0xd6, 0x51, 0x55, 0x80, 0x07, 0xdb, 0x43, 0x84, 0xb6, 0x50, 0xfc, 0xc0, 0x7e, 0x3b, 0x58, 0x6a, 0x27, 0xa4, 0xf7, 0xa0, 0x0a, 0xc8, 0xa6, 0xfe, 0xc2, 0xcd, 0x86, 0xae, 0x4b, 0xf1, 0x57, 0x0c, 0x41, 0xe6, 0xa4, 0x0c, 0x93, 0x1d, 0xb2, 0x7b, 0x2f, 0xaa, 0x15, 0xa8, 0xce, 0xdd, 0x52, 0xcf, 0xf7, 0x36, 0x2c, 0x4e, 0x6e, 0x23, 0xda, 0xec, 0x0f, 0xbc, 0x3a, 0x79, 0xb6, 0x80, 0x6e, 0x31, 0x6e, 0xfc, 0xc7, 0xb6, 0x81, 0x19, 0xbf, 0x46, 0xbc, 0x76, 0xa2, 0x60, 0x67, 0xa5, 0x3f, 0x29, 0x6d, 0xaf, 0xdb, 0xdc, 0x11, 0xc7, 0x7f, 0x77, 0x77, 0xe9, 0x72, 0x66, 0x0c, 0xf4, 0xb6, 0xa9, 0xb3, 0x69, 0xa6, 0x66, 0x5f, 0x02, 0xe0, 0xcc, 0x9b, 0x6e, 0xdf, 0xad, 0x13, 0x6b, 0x4f, 0xab, 0xe7, 0x23, 0xd2, 0x81, 0x3d, 0xb3, 0x13, 0x6c, 0xfd, 0xe9, 0xb6, 0xd0, 0x44, 0x32, 0x2f, 0xee, 0x29, 0x47, 0x95, 0x2e, 0x03, 0x1b, 0x73, 0xab, 0x5c, 0x60, 0x33, 0x49, 0xb3, 0x07, 0xbd, 0xc2, 0x7b, 0xc6, 0xcb, 0x8b, 0x8b, 0xbd, 0x7b, 0xd3, 0x23, 0x21, 0x9b, 0x80, 0x33, 0xa5, 0x81, 0xb5, 0x9e, 0xad, 0xeb, 0xb0, 0x9b, 0x3c, 0x4f, 0x3d, 0x22, 0x77, 0xd4, 0xf0, 0x34, 0x36, 0x24, 0xac, 0xc8, 0x17, 0x80, 0x47, 0x28, 0xb2, 0x5a, 0xb7, 0x97, 0x17, 0x2b, 0x4c, 0x5c, 0x21, 0xa2, 0x2f, 0x9c, 0x78, 0x39, 0xd6, 0x43, 0x00, 0x23, 0x2e, 0xb6, 0x6e, 0x53, 0xf3, 0x1c, 0x72, 0x3f, 0xa3, 0x7f, 0xe3, 0x87, 0xc7, 0xd3, 0xe5, 0x0b, 0xdf, 0x98, 0x13, 0xa3, 0x0e, 0x5b, 0xb1, 0x2c, 0xf4, 0xcd, 0x93, 0x0c, 0x40, 0xcf, 0xb4, 0xe1, 0xfc, 0x62, 0x25, 0x92, 0xa4, 0x95, 0x88, 0x79, 0x44, 0x94, 0xd5, 0x6d, 0x24, 0xea, 0x4b, 0x40, 0xc8, 0x9f, 0xc0, 0x59, 0x6c, 0xc9, 0xeb, 0xb9, 0x61, 0xc8, 0xcb, 0x10, 0xad, 0xde, 0x97, 0x6a, 0x5d, 0x60, 0x2b, 0x1c, 0x3f, 0x85, 0xb9, 0xb9, 0xa0, 0x01, 0xed, 0x3c, 0x6a, 0x4d, 0x3b, 0x14, 0x37, 0xf5, 0x20, 0x96, 0xcd, 0x19, 0x56, 0xd0, 0x42, 0xa5, 0x97, 0xd5, 0x61, 0xa5, 0x96, 0xec, 0xd3, 0xd1, 0x73, 0x5a, 0x8d, 0x57, 0x0e, 0xa0, 0xec, 0x27, 0x22, 0x5a, 0x2c, 0x4a, 0xaf, 0xf2, 0x63, 0x06, 0xd1, 0x52, 0x6c, 0x1a, 0xf3, 0xca, 0x6d, 0x9c, 0xf5, 0xa2, 0xc9, 0x8f, 0x47, 0xe1, 0xc4, 0x6d, 0xb9, 0xa3, 0x32, 0x34, 0xcf, 0xd4, 0xd8, 0x1f, 0x2c, 0x98, 0x53, 0x8a, 0x09, 0xeb, 0xe7, 0x69, 0x98, 0xd0, 0xd8, 0xfd, 0x25, 0x99, 0x7c, 0x7d, 0x25, 0x5c, 0x6d, 0x66, 0xec, 0xe6, 0xfa, 0x56, 0xf1, 0x11, 0x44, 0x95, 0x0f, 0x02, 0x77, 0x95, 0xe6, 0x53, 0x00, 0x8f, 0x4b, 0xd7, 0xca, 0x2d, 0xee, 0x85, 0xd8, 0xe9, 0x0f, 0x3d, 0xc3, 0x15, 0x13, 0x0c, 0xe2, 0xa0, 0x03, 0x75, 0xa3, 0x18, 0xc7, 0xc3, 0xd9, 0x7b, 0xe2, 0xc8, 0xce, 0x5b, 0x6d, 0xb4, 0x1a, 0x62, 0x54, 0xff, 0x26, 0x4f, 0xa6, 0x15, 0x5b, 0xae, 0xe3, 0xb0, 0x77, 0x3c, 0x0f, 0x49, 0x7c, 0x57, 0x3f, 0x19, 0xbb, 0x4f, 0x42, 0x40, 0x28, 0x1f, 0x0b, 0x1f, 0x4f, 0x7b, 0xe8, 0x57, 0xa4, 0xe5, 0x9d, 0x41, 0x6c, 0x06, 0xb4, 0xc5, 0x0f, 0xa0, 0x9e, 0x18, 0x10, 0xdd, 0xc6, 0xb1, 0x46, 0x7b, 0xae, 0xac, 0x5a, 0x36, 0x68, 0xd1, 0x1b, 0x6e, 0xca, 0xa9, 0x01, 0x44, 0x00, 0x16, 0xf3, 0x89, 0xf8, 0x0a, 0xcc, 0x4d, 0xb9, 0x77, 0x02, 0x5e, 0x7f, 0x59, 0x24, 0x38, 0x8c, 0x7e, 0x34, 0x0a, 0x73, 0x2e, 0x55, 0x44, 0x40, 0xe7, 0x65, 0x70, 0xf8, 0xdd, 0x71, 0xb7, 0xd6, 0x40, 0xb3, 0x45, 0x0d, 0x1f, 0xd5, 0xf0, 0x41, 0x0a, 0x18, 0xf9, 0xa3, 0x49, 0x4f, 0x70, 0x7c, 0x71, 0x7b, 0x79, 0xb4, 0xbf, 0x75, 0xc9, 0x84, 0x00, 0xb0, 0x96, 0xb2, 0x16, 0x53, 0xb5, 0xd2, 0x17, 0xcf, 0x35, 0x65, 0xc9, 0x59, 0x74, 0x56, 0xf7, 0x07, 0x03, 0x49, 0x7a, 0x07, 0x87, 0x63, 0x82, 0x9b, 0xc0, 0x1b, 0xb1, 0xcb, 0xc8, 0xfa, 0x04, 0xea, 0xdc, 0x9a, 0x6e, 0x3f, 0x66, 0x99, 0x58, 0x7a, 0x9e, 0x75, 0xc9, 0x4e, 0x5b, 0xab, 0x00, 0x36, 0xe0, 0xb2, 0xe7, 0x11, 0x39, 0x2c, 0xff, 0x00, 0x47, 0xd0, 0xd6, 0xb0, 0x5b, 0xd2, 0xa5, 0x88, 0xbc, 0x10, 0x97, 0x18, 0x95, 0x42, 0x59, 0xf1, 0xd8, 0x66, 0x78, 0xa5, 0x79, 0xa3, 0x12, 0x0f, 0x19, 0xcf, 0xb2, 0x96, 0x3f, 0x17, 0x7a, 0xeb, 0x70, 0xf2, 0xd4, 0x84, 0x48, 0x26, 0x26, 0x2e, 0x51, 0xb8, 0x02, 0x71, 0x27, 0x20, 0x68, 0xef, 0x5b, 0x38, 0x56, 0xfa, 0x85, 0x35, 0xaa, 0x2a, 0x88, 0xb2, 0xd4, 0x1f, 0x2a, 0x0e, 0x2f, 0xda, 0x76, 0x24, 0xc2, 0x85, 0x02, 0x72, 0xac, 0x4a, 0x2f, 0x56, 0x1f, 0x8f, 0x2f, 0x7a, 0x31, 0x8b, 0xfd, 0x5c, 0xaf, 0x96, 0x96, 0x14, 0x9e, 0x4a, 0xc8, 0x24, 0xad, 0x34, 0x60, 0x53, 0x8f, 0xdc, 0x25, 0x42, 0x1b, 0xee, 0xc2, 0xcc, 0x68, 0x18, 0x16, 0x2d, 0x06, 0xbb, 0xed, 0x0c, 0x40, 0xa3, 0x87, 0x19, 0x23, 0x49, 0xdb, 0x67, 0xa1, 0x18, 0xba, 0xda, 0x6c, 0xd5, 0xab, 0x01, 0x40, 0xee, 0x27, 0x32, 0x04, 0xf6, 0x28, 0xaa, 0xd1, 0xc1, 0x35, 0xf7, 0x70, 0x27, 0x9a, 0x65, 0x1e, 0x24, 0xd8, 0xc1, 0x4d, 0x75, 0xa6, 0x05, 0x9d, 0x76, 0xb9, 0x6a, 0x6f, 0xd8, 0x57, 0xde, 0xf5, 0xe0, 0xb3, 0x54, 0xb2, 0x7a, 0xb9, 0x37, 0xa5, 0x81, 0x5d, 0x16, 0xb5, 0xfa, 0xe4, 0x07, 0xff, 0x18, 0x22, 0x2c, 0x6d, 0x1e, 0xd2, 0x63, 0xbe, 0x68, 0xc9, 0x5f, 0x32, 0xd9, 0x08, 0xbd, 0x89, 0x5c, 0xd7, 0x62, 0x07, 0xae, 0x72, 0x64, 0x87, 0x56, 0x7f, 0x9a, 0x67, 0xda, 0xd7, 0x9a, 0xbe, 0xc3, 0x16, 0xf6, 0x83, 0xb1, 0x7f, 0x2d, 0x02, 0xbf, 0x07, 0xe0, 0xac, 0x8b, 0x5b, 0xc6, 0x16, 0x2c, 0xf9, 0x46, 0x97, 0xb3, 0xc2, 0x7c, 0xd1, 0xfe, 0xa4, 0x9b, 0x27, 0xf2, 0x3b, 0xa2, 0x90, 0x18, 0x71, 0x96, 0x25, 0x06, 0x52, 0x0c, 0x39, 0x2d, 0xa8, 0xb6, 0xad, 0x0d, 0x99, 0xf7, 0x01, 0x3f, 0xbc, 0x06, 0xc2, 0xc1, 0x7a, 0x56, 0x95, 0x00, 0xc8, 0xa7, 0x69, 0x64, 0x81, 0xc1, 0xcd, 0x33, 0xe9, 0xb1, 0x4e, 0x40, 0xb8, 0x2e, 0x79, 0xa5, 0xf5, 0xdb, 0x82, 0x57, 0x1b, 0xa9, 0x7b, 0xae, 0x3a, 0xd3, 0xe0, 0x47, 0x95, 0x15, 0xbb, 0x0e, 0x2b, 0x0f, 0x3b, 0xfc, 0xd1, 0xfd, 0x33, 0x03, 0x4e, 0xfc, 0x62, 0x45, 0xed, 0xdd, 0x7e, 0xe2, 0x08, 0x6d, 0xda, 0xe2, 0x60, 0x0d, 0x8c, 0xa7, 0x3e, 0x21, 0x4e, 0x8c, 0x2b, 0x0b, 0xdb, 0x2b, 0x04, 0x7c, 0x6a, 0x46, 0x4a, 0x56, 0x2e, 0xd7, 0x7b, 0x73, 0xd2, 0xd8, 0x41, 0xc4, 0xb3, 0x49, 0x73, 0x55, 0x12, 0x57, 0x71, 0x3b, 0x75, 0x36, 0x32, 0xef, 0xba, 0x34, 0x81, 0x69, 0xab, 0xc9, 0x0a, 0x68, 0xf4, 0x26, 0x11, 0xa4, 0x01, 0x26, 0xd7, 0xcb, 0x21, 0xb5, 0x86, 0x95, 0x56, 0x81, 0x86, 0xf7, 0xe5, 0x69, 0xd2, 0xff, 0x0f, 0x9e, 0x74, 0x5d, 0x04, 0x87, 0xdd, 0x2e, 0xb9, 0x97, 0xca, 0xfc, 0x5a, 0xbf, 0x9d, 0xd1, 0x02, 0xe6, 0x2f, 0xf6, 0x6c, 0xba, 0x87}
	}};

	std::array<std::vector<uint8_t>, c448_patternsSize> c448_signatures = {{
		std::vector<uint8_t>{0x53, 0x3a, 0x37, 0xf6, 0xbb, 0xe4, 0x57, 0x25, 0x1f, 0x02, 0x3c, 0x0d, 0x88, 0xf9, 0x76, 0xae, 0x2d, 0xfb, 0x50, 0x4a, 0x84, 0x3e, 0x34, 0xd2, 0x07, 0x4f, 0xd8, 0x23, 0xd4, 0x1a, 0x59, 0x1f, 0x2b, 0x23, 0x3f, 0x03, 0x4f, 0x62, 0x82, 0x81, 0xf2, 0xfd, 0x7a, 0x22, 0xdd, 0xd4, 0x7d, 0x78, 0x28, 0xc5, 0x9b, 0xd0, 0xa2, 0x1b, 0xfd, 0x39, 0x80, 0xff, 0x0d, 0x20, 0x28, 0xd4, 0xb1, 0x8a, 0x9d, 0xf6, 0x3e, 0x00, 0x6c, 0x5d, 0x1c, 0x2d, 0x34, 0x5b, 0x92, 0x5d, 0x8d, 0xc0, 0x0b, 0x41, 0x04, 0x85, 0x2d, 0xb9, 0x9a, 0xc5, 0xc7, 0xcd, 0xda, 0x85, 0x30, 0xa1, 0x13, 0xa0, 0xf4, 0xdb, 0xb6, 0x11, 0x49, 0xf0, 0x5a, 0x73, 0x63, 0x26, 0x8c, 0x71, 0xd9, 0x58, 0x08, 0xff, 0x2e, 0x65, 0x26, 0x00},
		std::vector<uint8_t>{0x26, 0xb8, 0xf9, 0x17, 0x27, 0xbd, 0x62, 0x89, 0x7a, 0xf1, 0x5e, 0x41, 0xeb, 0x43, 0xc3, 0x77, 0xef, 0xb9, 0xc6, 0x10, 0xd4, 0x8f, 0x23, 0x35, 0xcb, 0x0b, 0xd0, 0x08, 0x78, 0x10, 0xf4, 0x35, 0x25, 0x41, 0xb1, 0x43, 0xc4, 0xb9, 0x81, 0xb7, 0xe1, 0x8f, 0x62, 0xde, 0x8c, 0xcd, 0xf6, 0x33, 0xfc, 0x1b, 0xf0, 0x37, 0xab, 0x7c, 0xd7, 0x79, 0x80, 0x5e, 0x0d, 0xbc, 0xc0, 0xaa, 0xe1, 0xcb, 0xce, 0xe1, 0xaf, 0xb2, 0xe0, 0x27, 0xdf, 0x36, 0xbc, 0x04, 0xdc, 0xec, 0xbf, 0x15, 0x43, 0x36, 0xc1, 0x9f, 0x0a, 0xf7, 0xe0, 0xa6, 0x47, 0x29, 0x05, 0xe7, 0x99, 0xf1, 0x95, 0x3d, 0x2a, 0x0f, 0xf3, 0x34, 0x8a, 0xb2, 0x1a, 0xa4, 0xad, 0xaf, 0xd1, 0xd2, 0x34, 0x44, 0x1c, 0xf8, 0x07, 0xc0, 0x3a, 0x00},
		std::vector<uint8_t>{0x1f, 0x0a, 0x88, 0x88, 0xce, 0x25, 0xe8, 0xd4, 0x58, 0xa2, 0x11, 0x30, 0x87, 0x9b, 0x84, 0x0a, 0x90, 0x89, 0xd9, 0x99, 0xaa, 0xba, 0x03, 0x9e, 0xaf, 0x3e, 0x3a, 0xfa, 0x09, 0x0a, 0x09, 0xd3, 0x89, 0xdb, 0xa8, 0x2c, 0x4f, 0xf2, 0xae, 0x8a, 0xc5, 0xcd, 0xfb, 0x7c, 0x55, 0xe9, 0x4d, 0x5d, 0x96, 0x1a, 0x29, 0xfe, 0x01, 0x09, 0x94, 0x1e, 0x00, 0xb8, 0xdb, 0xde, 0xea, 0x6d, 0x3b, 0x05, 0x10, 0x68, 0xdf, 0x72, 0x54, 0xc0, 0xcd, 0xc1, 0x29, 0xcb, 0xe6, 0x2d, 0xb2, 0xdc, 0x95, 0x7d, 0xbb, 0x47, 0xb5, 0x1f, 0xd3, 0xf2, 0x13, 0xfb, 0x86, 0x98, 0xf0, 0x64, 0x77, 0x42, 0x50, 0xa5, 0x02, 0x89, 0x61, 0xc9, 0xbf, 0x8f, 0xfd, 0x97, 0x3f, 0xe5, 0xd5, 0xc2, 0x06, 0x49, 0x2b, 0x14, 0x0e, 0x00},
		std::vector<uint8_t>{0x7e, 0xee, 0xab, 0x7c, 0x4e, 0x50, 0xfb, 0x79, 0x9b, 0x41, 0x8e, 0xe5, 0xe3, 0x19, 0x7f, 0xf6, 0xbf, 0x15, 0xd4, 0x3a, 0x14, 0xc3, 0x43, 0x89, 0xb5, 0x9d, 0xd1, 0xa7, 0xb1, 0xb8, 0x5b, 0x4a, 0xe9, 0x04, 0x38, 0xac, 0xa6, 0x34, 0xbe, 0xa4, 0x5e, 0x3a, 0x26, 0x95, 0xf1, 0x27, 0x0f, 0x07, 0xfd, 0xcd, 0xf7, 0xc6, 0x2b, 0x8e, 0xfe, 0xaf, 0x00, 0xb4, 0x5c, 0x2c, 0x96, 0xba, 0x45, 0x7e, 0xb1, 0xa8, 0xbf, 0x07, 0x5a, 0x3d, 0xb2, 0x8e, 0x5c, 0x24, 0xf6, 0xb9, 0x23, 0xed, 0x4a, 0xd7, 0x47, 0xc3, 0xc9, 0xe0, 0x3c, 0x70, 0x79, 0xef, 0xb8, 0x7c, 0xb1, 0x10, 0xd3, 0xa9, 0x98, 0x61, 0xe7, 0x20, 0x03, 0xcb, 0xae, 0x6d, 0x6b, 0x8b, 0x82, 0x7e, 0x4e, 0x6c, 0x14, 0x30, 0x64, 0xff, 0x3c, 0x00},
		std::vector<uint8_t>{0x6a, 0x12, 0x06, 0x6f, 0x55, 0x33, 0x1b, 0x6c, 0x22, 0xac, 0xd5, 0xd5, 0xbf, 0xc5, 0xd7, 0x12, 0x28, 0xfb, 0xda, 0x80, 0xae, 0x8d, 0xec, 0x26, 0xbd, 0xd3, 0x06, 0x74, 0x3c, 0x50, 0x27, 0xcb, 0x48, 0x90, 0x81, 0x0c, 0x16, 0x2c, 0x02, 0x74, 0x68, 0x67, 0x5e, 0xcf, 0x64, 0x5a, 0x83, 0x17, 0x6c, 0x0d, 0x73, 0x23, 0xa2, 0xcc, 0xde, 0x2d, 0x80, 0xef, 0xe5, 0xa1, 0x26, 0x8e, 0x8a, 0xca, 0x1d, 0x6f, 0xbc, 0x19, 0x4d, 0x3f, 0x77, 0xc4, 0x49, 0x86, 0xeb, 0x4a, 0xb4, 0x17, 0x79, 0x19, 0xad, 0x8b, 0xec, 0x33, 0xeb, 0x47, 0xbb, 0xb5, 0xfc, 0x6e, 0x28, 0x19, 0x6f, 0xd1, 0xca, 0xf5, 0x6b, 0x4e, 0x7e, 0x0b, 0xa5, 0x51, 0x92, 0x34, 0xd0, 0x47, 0x15, 0x5a, 0xc7, 0x27, 0xa1, 0x05, 0x31, 0x00},
		std::vector<uint8_t>{0x55, 0x4b, 0xc2, 0x48, 0x08, 0x60, 0xb4, 0x9e, 0xab, 0x85, 0x32, 0xd2, 0xa5, 0x33, 0xb7, 0xd5, 0x78, 0xef, 0x47, 0x3e, 0xeb, 0x58, 0xc9, 0x8b, 0xb2, 0xd0, 0xe1, 0xce, 0x48, 0x8a, 0x98, 0xb1, 0x8d, 0xfd, 0xe9, 0xb9, 0xb9, 0x07, 0x75, 0xe6, 0x7f, 0x47, 0xd4, 0xa1, 0xc3, 0x48, 0x20, 0x58, 0xef, 0xc9, 0xf4, 0x0d, 0x2c, 0xa0, 0x33, 0xa0, 0x80, 0x1b, 0x63, 0xd4, 0x5b, 0x3b, 0x72, 0x2e, 0xf5, 0x52, 0xba, 0xd3, 0xb4, 0xcc, 0xb6, 0x67, 0xda, 0x35, 0x01, 0x92, 0xb6, 0x1c, 0x50, 0x8c, 0xf7, 0xb6, 0xb5, 0xad, 0xad, 0xc2, 0xc8, 0xd9, 0xa4, 0x46, 0xef, 0x00, 0x3f, 0xb0, 0x5c, 0xba, 0x5f, 0x30, 0xe8, 0x8e, 0x36, 0xec, 0x27, 0x03, 0xb3, 0x49, 0xca, 0x22, 0x9c, 0x26, 0x70, 0x83, 0x39, 0x00},
		std::vector<uint8_t>{0xc6, 0x50, 0xdd, 0xbb, 0x06, 0x01, 0xc1, 0x9c, 0xa1, 0x14, 0x39, 0xe1, 0x64, 0x0d, 0xd9, 0x31, 0xf4, 0x3c, 0x51, 0x8e, 0xa5, 0xbe, 0xa7, 0x0d, 0x3d, 0xcd, 0xe5, 0xf4, 0x19, 0x1f, 0xe5, 0x3f, 0x00, 0xcf, 0x96, 0x65, 0x46, 0xb7, 0x2b, 0xcc, 0x7d, 0x58, 0xbe, 0x2b, 0x9b, 0xad, 0xef, 0x28, 0x74, 0x39, 0x54, 0xe3, 0xa4, 0x4a, 0x23, 0xf8, 0x80, 0xe8, 0xd4, 0xf1, 0xcf, 0xce, 0x2d, 0x7a, 0x61, 0x45, 0x2d, 0x26, 0xda, 0x05, 0x89, 0x6f, 0x0a, 0x50, 0xda, 0x66, 0xa2, 0x39, 0xa8, 0xa1, 0x88, 0xb6, 0xd8, 0x25, 0xb3, 0x30, 0x5a, 0xd7, 0x7b, 0x73, 0xfb, 0xac, 0x08, 0x36, 0xec, 0xc6, 0x09, 0x87, 0xfd, 0x08, 0x52, 0x7c, 0x1a, 0x8e, 0x80, 0xd5, 0x82, 0x3e, 0x65, 0xca, 0xfe, 0x2a, 0x3d, 0x00},
		std::vector<uint8_t>{0xe3, 0x01, 0x34, 0x5a, 0x41, 0xa3, 0x9a, 0x4d, 0x72, 0xff, 0xf8, 0xdf, 0x69, 0xc9, 0x80, 0x75, 0xa0, 0xcc, 0x08, 0x2b, 0x80, 0x2f, 0xc9, 0xb2, 0xb6, 0xbc, 0x50, 0x3f, 0x92, 0x6b, 0x65, 0xbd, 0xdf, 0x7f, 0x4c, 0x8f, 0x1c, 0xb4, 0x9f, 0x63, 0x96, 0xaf, 0xc8, 0xa7, 0x0a, 0xbe, 0x6d, 0x8a, 0xef, 0x0d, 0xb4, 0x78, 0xd4, 0xc6, 0xb2, 0x97, 0x00, 0x76, 0xc6, 0xa0, 0x48, 0x4f, 0xe7, 0x6d, 0x76, 0xb3, 0xa9, 0x76, 0x25, 0xd7, 0x9f, 0x1c, 0xe2, 0x40, 0xe7, 0xc5, 0x76, 0x75, 0x0d, 0x29, 0x55, 0x28, 0x28, 0x6f, 0x71, 0x9b, 0x41, 0x3d, 0xe9, 0xad, 0xa3, 0xe8, 0xeb, 0x78, 0xed, 0x57, 0x36, 0x03, 0xce, 0x30, 0xd8, 0xbb, 0x76, 0x17, 0x85, 0xdc, 0x30, 0xdb, 0xc3, 0x20, 0x86, 0x9e, 0x1a, 0x00}
	}};



	for (size_t i=0; i<c448_messages.size(); i++) {
		auto Alice = make_Signature<C448>();
		Alice->set_secret(DSA<C448, lime::DSAtype::privateKey> (c448_secret_keys[i].cbegin()));

		Alice->derivePublic();
		BC_ASSERT_TRUE(memcmp(Alice->get_public().data(), c448_public_keys[i].data(), c448_public_keys[i].size())==0);
		DSA<C448, lime::DSAtype::signature> signature{};
		Alice->sign(c448_messages[i], signature);
		BC_ASSERT_TRUE(memcmp(signature.data(), c448_signatures[i].data(), c448_signatures[i].size())==0);

		auto Vera = make_Signature<C448>();
		Vera->set_public(DSA<C448, lime::DSAtype::publicKey>(c448_public_keys[i].cbegin()));
		BC_ASSERT_TRUE(Vera->verify(c448_messages[i], signature));
	}

#endif
}

static void hashMac_KDF_bench(uint64_t runTime_ms, size_t IKMsize) {
	size_t batch_size = 500;
	/* input lenght is the same used by X3DH */
	std::vector<uint8_t> IKM(IKMsize, 0);
	lime_tester::randomize(IKM.data(), IKM.size());
	std::string info{"The lime tester info string"};
	std::vector<uint8_t> salt(SHA512::ssize(), 0); // salt is the same used in X3DH
	std::array<uint8_t, 64> output;

	auto start = bctbx_get_cur_time_ms();
	uint64_t span=0;
	size_t runCount = 0;


	while (span<runTime_ms) {
		for (size_t i=0; i<batch_size; i++) {
			/* Run the HKDF function asking for 64 bytes(no use of the HKDF function requests more than that in the lime library) */
			HMAC_KDF<SHA512>(salt, IKM, info, output.data(), output.size());
		}
		span = bctbx_get_cur_time_ms() - start;
		runCount += batch_size;
	}

	auto freq = 1000*runCount/static_cast<double>(span);
	std::string freq_unit, period_unit;
	snprintSI(freq_unit, freq, "derivations/s");
	snprintSI(period_unit, 1/freq, "s/derivation");
	LIME_LOGI<<"Derive "<<int(runCount)<<" key material in "<<int(span)<<" ms : "<<period_unit<<" "<<freq_unit<<endl<<endl;
}

static void hashMac_KDF(void) {
	/* test patterns from RFC5869 generated for SHA512 using https://github.com/casebeer/python-hkdf */
	/* test A.1 */
	std::vector<uint8_t> IKM{0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b};
	std::vector<uint8_t> salt{0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c};
	std::vector<uint8_t> info{0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9};
	std::vector<uint8_t> OKM{0x83, 0x23, 0x90, 0x08, 0x6c, 0xda, 0x71, 0xfb, 0x47, 0x62, 0x5b, 0xb5, 0xce, 0xb1, 0x68, 0xe4, 0xc8, 0xe2, 0x6a, 0x1a, 0x16, 0xed, 0x34, 0xd9, 0xfc, 0x7f, 0xe9, 0x2c, 0x14, 0x81, 0x57, 0x93, 0x38, 0xda, 0x36, 0x2c, 0xb8, 0xd9, 0xf9, 0x25, 0xd7, 0xcb};
	std::vector<uint8_t> output;
	output.resize(OKM.size());
	HMAC_KDF<SHA512>(salt, IKM, info, output.data(), output.size());
	BC_ASSERT_TRUE(OKM==output);

	/* test A.2 */
	IKM.assign({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f});
	salt.assign({0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf});
	info.assign({0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff});
	OKM.assign({0xce, 0x6c, 0x97, 0x19, 0x28, 0x05, 0xb3, 0x46, 0xe6, 0x16, 0x1e, 0x82, 0x1e, 0xd1, 0x65, 0x67, 0x3b, 0x84, 0xf4, 0x00, 0xa2, 0xb5, 0x14, 0xb2, 0xfe, 0x23, 0xd8, 0x4c, 0xd1, 0x89, 0xdd, 0xf1, 0xb6, 0x95, 0xb4, 0x8c, 0xbd, 0x1c, 0x83, 0x88, 0x44, 0x11, 0x37, 0xb3, 0xce, 0x28, 0xf1, 0x6a, 0xa6, 0x4b, 0xa3, 0x3b, 0xa4, 0x66, 0xb2, 0x4d, 0xf6, 0xcf, 0xcb, 0x02, 0x1e, 0xcf, 0xf2, 0x35, 0xf6, 0xa2, 0x05, 0x6c, 0xe3, 0xaf, 0x1d, 0xe4, 0x4d, 0x57, 0x20, 0x97, 0xa8, 0x50, 0x5d, 0x9e, 0x7a, 0x93});
	output.resize(OKM.size());
	HMAC_KDF<SHA512>(salt, IKM, info, output.data(), output.size());
	BC_ASSERT_TRUE(OKM==output);

	/* test A.3 */
	IKM.assign({0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b});
	salt.clear();
	info.clear();
	OKM.assign({0xf5, 0xfa, 0x02, 0xb1, 0x82, 0x98, 0xa7, 0x2a, 0x8c, 0x23, 0x89, 0x8a, 0x87, 0x03, 0x47, 0x2c, 0x6e, 0xb1, 0x79, 0xdc, 0x20, 0x4c, 0x03, 0x42, 0x5c, 0x97, 0x0e, 0x3b, 0x16, 0x4b, 0xf9, 0x0f, 0xff, 0x22, 0xd0, 0x48, 0x36, 0xd0, 0xe2, 0x34, 0x3b, 0xac});
	output.resize(OKM.size());
	HMAC_KDF<SHA512>(salt, IKM, info, output.data(), output.size());
	BC_ASSERT_TRUE(OKM==output);

	/* test A.4 */
	IKM.assign({0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b, 0x0b});
	salt.assign({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c});
	info.assign({0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9});
	OKM.assign({0x74, 0x13, 0xe8, 0x99, 0x7e, 0x02, 0x06, 0x10, 0xfb, 0xf6, 0x82, 0x3f, 0x2c, 0xe1, 0x4b, 0xff, 0x01, 0x87, 0x5d, 0xb1, 0xca, 0x55, 0xf6, 0x8c, 0xfc, 0xf3, 0x95, 0x4d, 0xc8, 0xaf, 0xf5, 0x35, 0x59, 0xbd, 0x5e, 0x30, 0x28, 0xb0, 0x80, 0xf7, 0xc0, 0x68});
	output.resize(OKM.size());
	HMAC_KDF<SHA512>(salt, IKM, info, output.data(), output.size());
	BC_ASSERT_TRUE(OKM==output);

	/* test A.7 */
	IKM.assign({0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c, 0x0c});
	salt.clear();
	info.clear();
	OKM.assign({0x14, 0x07, 0xd4, 0x60, 0x13, 0xd9, 0x8b, 0xc6, 0xde, 0xce, 0xfc, 0xfe, 0xe5, 0x5f, 0x0f, 0x90, 0xb0, 0xc7, 0xf6, 0x3d, 0x68, 0xeb, 0x1a, 0x80, 0xea, 0xf0, 0x7e, 0x95, 0x3c, 0xfc, 0x0a, 0x3a, 0x52, 0x40, 0xa1, 0x55, 0xd6, 0xe4, 0xda, 0xa9, 0x65, 0xbb});
	output.resize(OKM.size());
	HMAC_KDF<SHA512>(salt, IKM, info, output.data(), output.size());
	BC_ASSERT_TRUE(OKM==output);


	/* Run benchmarks */
	if (bench) {
		size_t IKMsize = 0;
	#ifdef EC25519_ENABLED
		IKMsize = DSA<C255, lime::DSAtype::publicKey>::ssize()+4*X<C255, lime::Xtype::sharedSecret>::ssize();
		LIME_LOGI<<"Bench for SHA512 on Curve 25519 X3DH sized IKM("<<IKMsize<<" bytes)"<<endl;
		hashMac_KDF_bench(BENCH_TIMING_MS, IKMsize);
	#endif
	#ifdef EC448_ENABLED
		IKMsize = DSA<C448, lime::DSAtype::publicKey>::ssize()+4*X<C448, lime::Xtype::sharedSecret>::ssize();
		LIME_LOGI<<"Bench for SHA512 on Curve 448 X3DH sized IKM("<<IKMsize<<" bytes)"<<endl;
		hashMac_KDF_bench(BENCH_TIMING_MS, IKMsize);
	#endif
	}
}

static void AEAD(void) {
	std::vector<uint8_t> cipher{};
	std::vector<uint8_t> tag{};
	std::vector<uint8_t> plain{};

	/* Test vectors for AES256-GCM128 from IEEE P1619.1/D22 - Annex D.3 */
	tag.resize(AES256GCM::tagSize());
	/* Test D3.1*/
	std::vector<uint8_t> key{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
	std::vector<uint8_t> IV{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
	std::vector<uint8_t> pattern_plain{0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00};
	std::vector<uint8_t> pattern_cipher{0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18};
	std::vector<uint8_t> pattern_tag{0xd0, 0xd1, 0xc8, 0xa7, 0x99, 0x99, 0x6b, 0xf0, 0x26, 0x5b, 0x98, 0xb5, 0xd4, 0x8a, 0xb9, 0x19};
	std::vector<uint8_t> AD{};
	AD.clear();
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), AD.data(), AD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);

	/* Test D3.2 */
	key.assign({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
	IV.assign({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
	AD.assign({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
	pattern_plain.clear();
	pattern_cipher.clear();
	pattern_tag.assign({0x2d, 0x45, 0x55, 0x2d, 0x85, 0x75, 0x92, 0x2b, 0x3c, 0xa3, 0xcc, 0x53, 0x84, 0x42, 0xfa, 0x26});
	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(tag==pattern_tag);

	/* Test D3.3 */
	key.assign({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
	IV.assign({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
	AD.assign({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
	pattern_plain.assign({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
	pattern_cipher.assign({0xce, 0xa7, 0x40, 0x3d, 0x4d, 0x60, 0x6b, 0x6e, 0x07, 0x4e, 0xc5, 0xd3, 0xba, 0xf3, 0x9d, 0x18});
	pattern_tag.assign({0xae, 0x9b, 0x17, 0x71, 0xdb, 0xa9, 0xcf, 0x62, 0xb3, 0x9b, 0xe0, 0x17, 0x94, 0x03, 0x30, 0xb4});
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), AD.data(), AD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);

	/* Test D3.4 */
	key.assign({0xfb, 0x76, 0x15, 0xb2, 0x3d, 0x80, 0x89, 0x1d, 0xd4, 0x70, 0x98, 0x0b, 0xc7, 0x95, 0x84, 0xc8, 0xb2, 0xfb, 0x64, 0xce, 0x60, 0x97, 0x8f, 0x4d, 0x17, 0xfc, 0xe4, 0x5a, 0x49, 0xe8, 0x30, 0xb7});
	IV.assign({0xdb, 0xd1, 0xa3, 0x63, 0x60, 0x24, 0xb7, 0xb4, 0x02, 0xda, 0x7d, 0x6f});
	AD.clear();
	pattern_plain.assign({0xa8, 0x45, 0x34, 0x8e, 0xc8, 0xc5, 0xb5, 0xf1, 0x26, 0xf5, 0x0e, 0x76, 0xfe, 0xfd, 0x1b, 0x1e});
	pattern_cipher.assign({0x5d, 0xf5, 0xd1, 0xfa, 0xbc, 0xbb, 0xdd, 0x05, 0x15, 0x38, 0x25, 0x24, 0x44, 0x17, 0x87, 0x04});
	pattern_tag.assign({0x4c, 0x43, 0xcc, 0xe5, 0xa5, 0x74, 0xd8, 0xa8, 0x8b, 0x43, 0xd4, 0x35, 0x3b, 0xd6, 0x0f, 0x9f});
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), AD.data(), AD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);

	/* Test D3.5 */
	key.assign({0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f});
	IV.assign({0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b});
	AD.assign({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13});
	pattern_plain.assign({0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37});
	pattern_cipher.assign({0x59, 0x1b, 0x1f, 0xf2, 0x72, 0xb4, 0x32, 0x04, 0x86, 0x8f, 0xfc, 0x7b, 0xc7, 0xd5, 0x21, 0x99, 0x35, 0x26, 0xb6, 0xfa, 0x32, 0x24, 0x7c, 0x3c});
	pattern_tag.assign({0x7d, 0xe1, 0x2a, 0x56, 0x70, 0xe5, 0x70, 0xd8, 0xca, 0xe6, 0x24, 0xa1, 0x6d, 0xf0, 0x9c, 0x08});
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), AD.data(), AD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);

	/* Test D3.6 */
	key.assign({0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f});
	IV.assign({0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b});
	AD.assign({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff});
	pattern_plain.assign({0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f});
	pattern_cipher.assign({0x59, 0x1b, 0x1f, 0xf2, 0x72, 0xb4, 0x32, 0x04, 0x86, 0x8f, 0xfc, 0x7b, 0xc7, 0xd5, 0x21, 0x99, 0x35, 0x26, 0xb6, 0xfa, 0x32, 0x24, 0x7c, 0x3c, 0x40, 0x57, 0xf3, 0xea, 0xe7, 0x54, 0x8c, 0xef});
	pattern_tag.assign({0xa1, 0xde, 0x55, 0x36, 0xe9, 0x7e, 0xdd, 0xdc, 0xcd, 0x26, 0xee, 0xb1, 0xb5, 0xff, 0x7b, 0x32});
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());
	std::vector<uint8_t> repeatAD{};
	for (auto i=0; i<256; i++) {
		repeatAD.insert(repeatAD.end(), AD.cbegin(), AD.cend());
	}

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), repeatAD.data(), repeatAD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), repeatAD.data(), repeatAD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);

	/* Test D3.7 */
	key.assign({0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f});
	IV.assign({0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b});
	AD.assign({0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f});
	pattern_plain.assign({0x00, 0x01, 0x02, 0x03, 0x04, 0x05, 0x06, 0x07, 0x08, 0x09, 0x0a, 0x0b, 0x0c, 0x0d, 0x0e, 0x0f, 0x10, 0x11, 0x12, 0x13, 0x14, 0x15, 0x16, 0x17, 0x18, 0x19, 0x1a, 0x1b, 0x1c, 0x1d, 0x1e, 0x1f, 0x20, 0x21, 0x22, 0x23, 0x24, 0x25, 0x26, 0x27, 0x28, 0x29, 0x2a, 0x2b, 0x2c, 0x2d, 0x2e, 0x2f, 0x30, 0x31, 0x32, 0x33, 0x34, 0x35, 0x36, 0x37, 0x38, 0x39, 0x3a, 0x3b, 0x3c, 0x3d, 0x3e, 0x3f, 0x40, 0x41, 0x42, 0x43, 0x44, 0x45, 0x46, 0x47, 0x48, 0x49, 0x4a, 0x4b, 0x4c, 0x4d, 0x4e, 0x4f, 0x50, 0x51, 0x52, 0x53, 0x54, 0x55, 0x56, 0x57, 0x58, 0x59, 0x5a, 0x5b, 0x5c, 0x5d, 0x5e, 0x5f, 0x60, 0x61, 0x62, 0x63, 0x64, 0x65, 0x66, 0x67, 0x68, 0x69, 0x6a, 0x6b, 0x6c, 0x6d, 0x6e, 0x6f, 0x70, 0x71, 0x72, 0x73, 0x74, 0x75, 0x76, 0x77, 0x78, 0x79, 0x7a, 0x7b, 0x7c, 0x7d, 0x7e, 0x7f, 0x80, 0x81, 0x82, 0x83, 0x84, 0x85, 0x86, 0x87, 0x88, 0x89, 0x8a, 0x8b, 0x8c, 0x8d, 0x8e, 0x8f, 0x90, 0x91, 0x92, 0x93, 0x94, 0x95, 0x96, 0x97, 0x98, 0x99, 0x9a, 0x9b, 0x9c, 0x9d, 0x9e, 0x9f, 0xa0, 0xa1, 0xa2, 0xa3, 0xa4, 0xa5, 0xa6, 0xa7, 0xa8, 0xa9, 0xaa, 0xab, 0xac, 0xad, 0xae, 0xaf, 0xb0, 0xb1, 0xb2, 0xb3, 0xb4, 0xb5, 0xb6, 0xb7, 0xb8, 0xb9, 0xba, 0xbb, 0xbc, 0xbd, 0xbe, 0xbf, 0xc0, 0xc1, 0xc2, 0xc3, 0xc4, 0xc5, 0xc6, 0xc7, 0xc8, 0xc9, 0xca, 0xcb, 0xcc, 0xcd, 0xce, 0xcf, 0xd0, 0xd1, 0xd2, 0xd3, 0xd4, 0xd5, 0xd6, 0xd7, 0xd8, 0xd9, 0xda, 0xdb, 0xdc, 0xdd, 0xde, 0xdf, 0xe0, 0xe1, 0xe2, 0xe3, 0xe4, 0xe5, 0xe6, 0xe7, 0xe8, 0xe9, 0xea, 0xeb, 0xec, 0xed, 0xee, 0xef, 0xf0, 0xf1, 0xf2, 0xf3, 0xf4, 0xf5, 0xf6, 0xf7, 0xf8, 0xf9, 0xfa, 0xfb, 0xfc, 0xfd, 0xfe, 0xff});
	pattern_cipher.assign({0x79, 0x3b, 0x3f, 0xd2, 0x52, 0x94, 0x12, 0x24, 0xa6, 0xaf, 0xdc, 0x5b, 0xe7, 0xf5, 0x01, 0xb9, 0x15, 0x06, 0x96, 0xda, 0x12, 0x04, 0x5c, 0x1c, 0x60, 0x77, 0xd3, 0xca, 0xc7, 0x74, 0xac, 0xcf, 0xc3, 0xd5, 0x30, 0xd8, 0x48, 0xd6, 0x65, 0xd8, 0x1a, 0x49, 0xcb, 0xb5, 0x00, 0xb8, 0x8b, 0xbb, 0x62, 0x4a, 0xe6, 0x1d, 0x16, 0x67, 0x22, 0x9c, 0x30, 0x2d, 0xc6, 0xff, 0x0b, 0xb4, 0xd7, 0x0b, 0xdb, 0xbc, 0x85, 0x66, 0xd6, 0xf5, 0xb1, 0x58, 0xda, 0x99, 0xa2, 0xff, 0x2e, 0x01, 0xdd, 0xa6, 0x29, 0xb8, 0x9c, 0x34, 0xad, 0x1e, 0x5f, 0xeb, 0xa7, 0x0e, 0x7a, 0xae, 0x43, 0x28, 0x28, 0x9c, 0x36, 0x29, 0xb0, 0x58, 0x83, 0x50, 0x58, 0x1c, 0xa8, 0xb9, 0x7c, 0xcf, 0x12, 0x58, 0xfa, 0x3b, 0xbe, 0x2c, 0x50, 0x26, 0x04, 0x7b, 0xa7, 0x26, 0x48, 0x96, 0x9c, 0xff, 0x8b, 0xa1, 0x0a, 0xe3, 0x0e, 0x05, 0x93, 0x5d, 0xf0, 0xc6, 0x93, 0x74, 0x18, 0x92, 0xb7, 0x6f, 0xaf, 0x67, 0x13, 0x3a, 0xbd, 0x2c, 0xf2, 0x03, 0x11, 0x21, 0xbd, 0x8b, 0xb3, 0x81, 0x27, 0xa4, 0xd2, 0xee, 0xde, 0xea, 0x13, 0x27, 0x64, 0x94, 0xf4, 0x02, 0xcd, 0x7c, 0x10, 0x7f, 0xb3, 0xec, 0x3b, 0x24, 0x78, 0x48, 0x34, 0x33, 0x8e, 0x55, 0x43, 0x62, 0x87, 0x09, 0x2a, 0xc4, 0xa2, 0x6f, 0x5e, 0xa7, 0xea, 0x4a, 0xd6, 0x8d, 0x73, 0x15, 0x16, 0x39, 0xb0, 0x5b, 0x24, 0xe6, 0x8b, 0x98, 0x16, 0xd1, 0x39, 0x83, 0x76, 0xd8, 0xe4, 0x13, 0x85, 0x94, 0x75, 0x8d, 0xb9, 0xad, 0x3b, 0x40, 0x92, 0x59, 0xb2, 0x6d, 0xcf, 0xc0, 0x6e, 0x72, 0x2b, 0xe9, 0x87, 0xb3, 0x76, 0x7f, 0x70, 0xa7, 0xb8, 0x56, 0xb7, 0x74, 0xb1, 0xba, 0x26, 0x85, 0xb3, 0x68, 0x09, 0x14, 0x29, 0xfc, 0xcb, 0x8d, 0xcd, 0xde, 0x09, 0xe4});
	pattern_tag.assign({0x87, 0xec, 0x83, 0x7a, 0xbf, 0x53, 0x28, 0x55, 0xb2, 0xce, 0xa1, 0x69, 0xd6, 0x94, 0x3f, 0xcd});
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), AD.data(), AD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);

	/* Test D3.8 */
	key.assign({0xfb, 0x76, 0x15, 0xb2, 0x3d, 0x80, 0x89, 0x1d, 0xd4, 0x70, 0x98, 0x0b, 0xc7, 0x95, 0x84, 0xc8, 0xb2, 0xfb, 0x64, 0xce, 0x60, 0x97, 0x87, 0x8d, 0x17, 0xfc, 0xe4, 0x5a, 0x49, 0xe8, 0x30, 0xb7});
	IV.assign({0xdb, 0xd1, 0xa3, 0x63, 0x60, 0x24, 0xb7, 0xb4, 0x02, 0xda, 0x7d, 0x6f});
	AD.assign({0x36});
	pattern_plain.assign({0xa9});
	pattern_cipher.assign({0x0a});
	pattern_tag.assign({0xbe, 0x98, 0x7d, 0x00, 0x9a, 0x4b, 0x34, 0x9a, 0xa8, 0x0c, 0xb9, 0xc4, 0xeb, 0xc1, 0xe9, 0xf4});
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), AD.data(), AD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);

	/* Test D3.9 */
	key.assign({0xf8, 0xd4, 0x76, 0xcf, 0xd6, 0x46, 0xea, 0x6c, 0x23, 0x84, 0xcb, 0x1c, 0x27, 0xd6, 0x19, 0x5d, 0xfe, 0xf1, 0xa9, 0xf3, 0x7b, 0x9c, 0x8d, 0x21, 0xa7, 0x9c, 0x21, 0xf8, 0xcb, 0x90, 0xd2, 0x89});
	IV.assign({0xdb, 0xd1, 0xa3, 0x63, 0x60, 0x24, 0xb7, 0xb4, 0x02, 0xda, 0x7d, 0x6f});
	AD.assign({0x7b, 0xd8, 0x59, 0xa2, 0x47, 0x96, 0x1a, 0x21, 0x82, 0x3b, 0x38, 0x0e, 0x9f, 0xe8, 0xb6, 0x50, 0x82, 0xba, 0x61, 0xd3});
	pattern_plain.assign({0x90, 0xae, 0x61, 0xcf, 0x7b, 0xae, 0xbd, 0x4c, 0xad, 0xe4, 0x94, 0xc5, 0x4a, 0x29, 0xae, 0x70, 0x26, 0x9a, 0xec, 0x71});
	pattern_cipher.assign({0xce, 0x20, 0x27, 0xb4, 0x7a, 0x84, 0x32, 0x52, 0x01, 0x34, 0x65, 0x83, 0x4d, 0x75, 0xfd, 0x0f, 0x07, 0x29, 0x75, 0x2e});
	pattern_tag.assign({0xac, 0xd8, 0x83, 0x38, 0x37, 0xab, 0x0e, 0xde, 0x84, 0xf4, 0x74, 0x8d, 0xa8, 0x89, 0x9c, 0x15});
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), AD.data(), AD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);

	/* Test D3.10 */
	key.assign({0xdb, 0xbc, 0x85, 0x66, 0xd6, 0xf5, 0xb1, 0x58, 0xda, 0x99, 0xa2, 0xff, 0x2e, 0x01, 0xdd, 0xa6, 0x29, 0xb8, 0x9c, 0x34, 0xad, 0x1e, 0x5f, 0xeb, 0xa7, 0x0e, 0x7a, 0xae, 0x43, 0x28, 0x28, 0x9c});
	IV.assign({0xcf, 0xc0, 0x6e, 0x72, 0x2b, 0xe9, 0x87, 0xb3, 0x76, 0x7f, 0x70, 0xa7, 0xb8, 0x56, 0xb7, 0x74});
	AD.clear();
	pattern_plain.assign({0xce, 0x20, 0x27, 0xb4, 0x7a, 0x84, 0x32, 0x52, 0x01, 0x34, 0x65, 0x83, 0x4d, 0x75, 0xfd, 0x0f});
	pattern_cipher.assign({0xdc, 0x03, 0xe5, 0x24, 0x83, 0x0d, 0x30, 0xf8, 0x8e, 0x19, 0x7f, 0x3a, 0xca, 0xce, 0x66, 0xef});
	pattern_tag.assign({0x99, 0x84, 0xef, 0xf6, 0x90, 0x57, 0x55, 0xd1, 0x83, 0x6f, 0x2d, 0xb0, 0x40, 0x89, 0x63, 0x4c});
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), AD.data(), AD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);

	/* Test D3.11 */
	key.assign({0x0e, 0x05, 0x93, 0x5d, 0xf0, 0xc6, 0x93, 0x74, 0x18, 0x92, 0xb7, 0x6f, 0xaf, 0x67, 0x13, 0x3a, 0xbd, 0x2c, 0xf2, 0x03, 0x11, 0x21, 0xbd, 0x8b, 0xb3, 0x81, 0x27, 0xa4, 0xd2, 0xee, 0xde, 0xea});
	IV.assign({0x74, 0xb1, 0xba, 0x26, 0x85, 0xb3, 0x68, 0x09, 0x14, 0x29, 0xfc, 0xcb, 0x8d, 0xcd, 0xde, 0x09, 0xe4});
	AD.assign({0x7b, 0xd8, 0x59, 0xa2, 0x47, 0x96, 0x1a, 0x21, 0x82, 0x3b, 0x38, 0x0e, 0x9f, 0xe8, 0xb6, 0x50, 0x82, 0xba, 0x61, 0xd3});
	pattern_plain.assign({0x90, 0xae, 0x61, 0xcf, 0x7b, 0xae, 0xbd, 0x4c, 0xad, 0xe4, 0x94, 0xc5, 0x4a, 0x29, 0xae, 0x70, 0x26, 0x9a, 0xec, 0x71});
	pattern_cipher.assign({0x6b, 0xe6, 0x5e, 0x56, 0x06, 0x6c, 0x40, 0x56, 0x73, 0x8c, 0x03, 0xfe, 0x23, 0x20, 0x97, 0x4b, 0xa3, 0xf6, 0x5e, 0x09});
	pattern_tag.assign({0x61, 0x08, 0xdc, 0x41, 0x7b, 0xf3, 0x2f, 0x7f, 0xb7, 0x55, 0x4a, 0xe5, 0x2f, 0x08, 0x8f, 0x87});
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), AD.data(), AD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);

	/* Test D3.12 */
	key.assign({0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00});
	IV.assign({0x02, 0xcb, 0xbc, 0x7a, 0x03, 0xeb, 0x4d, 0xe3, 0x9d, 0x80, 0xd1, 0xeb, 0xc9, 0x88, 0xbf, 0xdf});
	AD.assign({0x68, 0x8e, 0x1a, 0xa9, 0x84, 0xde, 0x92, 0x6d, 0xc7, 0xb4, 0xc4, 0x7f, 0x44});
	pattern_plain.assign({0xa2, 0xaa, 0xb3, 0xad, 0x8b, 0x17, 0xac, 0xdd, 0xa2, 0x88, 0x42, 0x6c, 0xd7, 0xc4, 0x29, 0xb7, 0xca, 0x86, 0xb7, 0xac, 0xa0, 0x58, 0x09, 0xc7, 0x0c, 0xe8, 0x2d, 0xb2, 0x57, 0x11, 0xcb, 0x53, 0x02, 0xeb, 0x27, 0x43, 0xb0, 0x36, 0xf3, 0xd7, 0x50, 0xd6, 0xcf, 0x0d, 0xc0, 0xac, 0xb9, 0x29, 0x50, 0xd5, 0x46, 0xdb, 0x30, 0x8f, 0x93, 0xb4, 0xff, 0x24, 0x4a, 0xfa, 0x9d, 0xc7, 0x2b, 0xcd, 0x75, 0x8d, 0x2c});
	pattern_cipher.assign({0xee, 0x62, 0x55, 0x2a, 0xeb, 0xc0, 0xc3, 0xc7, 0xda, 0xae, 0x12, 0xbb, 0x6c, 0x32, 0xca, 0x5a, 0x00, 0x5f, 0x4a, 0x1a, 0xaa, 0xb0, 0x04, 0xed, 0x0f, 0x0b, 0x30, 0xab, 0xbf, 0x15, 0xac, 0xf4, 0xc5, 0x0c, 0x59, 0x66, 0x2d, 0x4b, 0x44, 0x68, 0x41, 0x95, 0x44, 0xe7, 0xf9, 0x81, 0x97, 0x35, 0x63, 0xce, 0x55, 0x6a, 0xe5, 0x08, 0x59, 0xee, 0x09, 0xb1, 0x4d, 0x31, 0xa0, 0x53, 0x98, 0x6f, 0x9a, 0xc8, 0x9b});
	pattern_tag.assign({0x9c, 0xd0, 0xdb, 0x93, 0x6e, 0x26, 0xd4, 0x4b, 0xe9, 0x74, 0xba, 0x86, 0x82, 0x85, 0xa2, 0xe1});
	cipher.resize(pattern_plain.size());
	plain.resize(pattern_plain.size());

	AEAD_encrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_plain.data(), pattern_plain.size(), AD.data(), AD.size(), tag.data(), tag.size(), cipher.data());
	BC_ASSERT_TRUE(cipher==pattern_cipher);
	BC_ASSERT_TRUE(tag==pattern_tag);
	BC_ASSERT_TRUE(AEAD_decrypt<AES256GCM>(key.data(), key.size(), IV.data(), IV.size(), pattern_cipher.data(), pattern_cipher.size(), AD.data(), AD.size(), pattern_tag.data(), pattern_tag.size(), plain.data()));
	BC_ASSERT_TRUE(plain==pattern_plain);
}

/**
 * @brief Test the Random Number Generator used to generate keys Id
 * The Id generation gives a 31 bits unsigned integer, is used when RNG->randomize function returns an uint32_t value
 * This test doesn't really test the quality of the RNG, just to point obvious mistakes in the implementation
 * It computes the mean and standard deviation of the generated number
 * Being a discrete uniform distribution, standard deviation is supposed to be
 * (max-min)/sqrt(12), in our case (0x7FFFFFFF - 0)/sqrt(12).
 * To get an more readable perspective, mean and sqrt are divided by 0x7FFFFFFF
 * and result are tested agains 0.5 and 1/sqrt(12)
 *
 */
static void RNG_test(void) {
	constexpr size_t NB_INT31_TESTED=10000;

	/* init the RNG */
	auto rng_source = make_RNG();
	uint32_t random_uint31 = rng_source->randomize();

	long double m0=static_cast<long double>(random_uint31),
	     s0=0.0,
	     m1=0.0;

	size_t i=2;
	for (; i<=NB_INT31_TESTED; i++) {
		random_uint31 = rng_source->randomize();
		auto random_double = static_cast<long double>(random_uint31);
		m1 = m0 + (random_double - m0)/static_cast<long double>(i);
		s0 +=  (random_double - m0)*(random_double  - m1);
		m0 = m1;
	}

	/* mean/0x7FFFFFFF shall be around 0.5 */
	m0 = m0/(long double)0x7FFFFFFF;
	if (m0>0.49 && m0<0.51) {
		BC_PASS("RNG mean value ok");
	} else {
		LIME_LOGE << NB_INT31_TESTED << " 31 bits unsigned integers generated Mean " << m0 <<" expected around 0.5" <<std::endl;
		BC_FAIL("RNG mean value incorrect");
	}

	/* sigma value/0x7FFFFFFF shall be around 1/sqrt(12)[0.288675]*/
	s0 = std::sqrt(s0/i-1)/(long double)0x7FFFFFFF;
	if (s0>0.278 && s0<0.299) {
		BC_PASS("RNG sigma value ok");
	} else {
		LIME_LOGE << NB_INT31_TESTED << " 31 bits unsigned integers generated Sigma " << s0 <<" expected around 0.288675"<<std::endl;
		BC_FAIL("RNG sigma value incorrect");
	}

	LIME_LOGD << NB_INT31_TESTED << " 31 bits unsigned integers generated Mean " << m0 << " Sigma "<<s0<<std::endl;
}

static test_t tests[] = {
	TEST_NO_TAG("Key Exchange", exchange),
	TEST_NO_TAG("Signature", signAndVerify),
	TEST_NO_TAG("HKDF", hashMac_KDF),
	TEST_NO_TAG("AEAD", AEAD),
	TEST_NO_TAG("RNG", RNG_test),
};

test_suite_t lime_crypto_test_suite = {
	"Crypto",
	NULL,
	NULL,
	NULL,
	NULL,
	sizeof(tests) / sizeof(tests[0]),
	tests
};
